1. Details
1.1 Libraries
source("R_rainclouds.R")
source("summarySE.R")
library(psych)
library(ordinal)
library(brms)
library(fs)
library(patchwork) #devtools::install_github("thomasp85/patchwork")
library(easystats) #devtools::install_github("easystats/easystats")
library(sjPlot)
library(httr)
library(kableExtra)
library(tidyverse)
theme_set(theme_classic(base_size = 15))
options(mc.cores = parallel::detectCores()) #run on multiple cores)
options("scipen"=10, "digits"=4)
Note: for the code chunk the language is listed, but all except for r chunks are executed in the terminal
1.2 Data description
Data of the Theory-of-Mind functional localiser and Individual Differences in Anthropomorphism Questionnaire are from five different studies.
Dataset_1: Bangor Imaging Unit; EMBOTS; n=29 (including 1 pilot scan); full dataset and publication: Cross…Hortensius (2019) PTRB.
Dataset_2: Centre for Cognitive NeuroImaging; SHAREDBOTS; n=35 (including 2 pilot scans) publication: Hortensius & Cross, in preparation.
Dataset_3: Centre for Cognitive NeuroImaging; Two studies with the same parameters: n=22 (including 2 pilot scans). Social_Gradient_1; n=10 (pilot experiment) and BOLDlight; n=12.
Dataset_4: Centre for Cognitive NeuroImaging; GAMEBOTS; n=22.
Get info for table S1:
#load data
DF.dataset1 <- read_tsv(file = "experiment1/dataset_1/participants.tsv")
Parsed with column specification:
cols(
participant_id = [31mcol_character()[39m,
age = [32mcol_double()[39m,
sex = [31mcol_character()[39m,
group = [31mcol_character()[39m
)
DF.dataset2 <- read_tsv(file = "experiment1/dataset_2/participants.tsv")
Parsed with column specification:
cols(
participant_id = [31mcol_character()[39m,
age = [32mcol_double()[39m,
sex = [31mcol_character()[39m,
group = [31mcol_character()[39m
)
DF.dataset3 <- read_tsv(file = "experiment1/dataset_3/participants.tsv")
Parsed with column specification:
cols(
participant_id = [31mcol_character()[39m,
age = [32mcol_double()[39m,
sex = [31mcol_character()[39m,
group = [31mcol_character()[39m
)
DF.dataset4 <- read_tsv(file = "experiment1/dataset_4/participants.tsv")
Parsed with column specification:
cols(
participant_id = [31mcol_character()[39m,
age = [32mcol_double()[39m,
sex = [31mcol_character()[39m,
group = [31mcol_character()[39m
)
#combine data
bind_rows(DF.dataset1, DF.dataset2, DF.dataset3, DF.dataset4, .id = "dataset") %>%
group_by(dataset) %>%
summarise(mean = mean(age),
sd = sd(age)) %>%
knitr::kable(., "html", caption = "Age") %>%
kable_styling("striped")
bind_rows(DF.dataset1, DF.dataset2, DF.dataset3, DF.dataset4, .id = "dataset") %>%
group_by(dataset, sex) %>%
tally() %>%
knitr::kable(., "html", caption = "Sex") %>%
kable_styling("striped")
Sex
| dataset |
sex |
n |
| 1 |
F |
20 |
| 1 |
M |
9 |
| 2 |
F |
22 |
| 2 |
M |
13 |
| 3 |
F |
12 |
| 3 |
M |
10 |
| 4 |
M |
22 |
1.3 Neuroimaging procedure
All participants completed a Theory-of-Mind localiser (Jacoby et al., 2016; Richardson et al. 2018) and an anatomical scan either in the same session or in two seperate sessions. During the localiser participants passively viewed a short 5.6 min animated film (Partly Cloudy). This movie includes scenes depicting pain (e.g. an alligator biting the main character) and events that trigger mentalizing (e.g. the main character revealing its intention). For dataset_3 and dataset_4 a fieldmap was collected as well. At the end of each experiment participants completed the Individual Differences in Anthropomorphism Questionnaire (IDAQ) (Waytz et al., 2010).
BOLD:
Dataset_1: 3x3x3.5mm voxels, 32 slices, repetition time = 2s, echo time = 30ms
Dataset_2: 3mm isotropic, 37 slices, TR = 2s, TE = 30ms
Dataset_3: 2mm isotropic, 68 slices, TR = 2s, TE = 26ms
Dataset_4: 2.75 x 2.75 x 4mm, 32 slices, TR = 2s, TE = 13 and 31ms
T1W:
Dataset_1: 1mm isotropic resolution, TR = 12ms, TE = 3.47 / 5.15 / 6.83 / 8.52 / 10.20ms (SENSE)
Dataset_2 - 4: 1mm isotropic resolution, TR = 2.3s, TE = 29.6ms (ADNI)
Fieldmaps:
Dataset_1: no, so –use-syn-sdc
Dataset_2: no, so –use-syn-sdc
Dataset_3: yes
Dataset_4: yes
2. BIDS dataset
2.1 Creating the BIDS dataset
For this you need HeuDiConv Heuristic DICOM Converter.
Based on the tutorial by Franklin Feingold.
Dowload the latest version of Heudiconv (we used 0.6.0.dev1):
docker pull nipy/heudiconv:latest
If on the GRID do:
singularity pull docker://nipy/heudiconv:latest
Create the info file (dataset_2 - 4):
docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_3/sourcedata/sub-{subject}/*.IMA -o /base/dataset_3 -f convertall -s 315 -c none --overwrite
For dataset_1 we first need to convert the .dcm from jpeg-2000 lossless to uncompressed dcm (thanks to Michele Svanera for the code):
python3 convert_all_compressed_dicom.py
Create the info file (dataset_1):
docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1 -f convertall -s 129 -ss 01 -c none --overwrite
Get the info file:
cp /Volumes/Project0255/code/.heudiconv/301/info/dicominfo.tsv /Volumes/Project0255/code
2.2 Create the heuristic file
Create the following python file and save it in the code folder. There is one functional task (func_movie) and one anatomical (t1w). Dataset_3 and 4 have a field map as well (fmap_phase and fmap_magnitude)
Create a heuristic to automatically convert the files:
import os
def create_key(template, outtype=('nii.gz',), annotation_classes=None):
if template is None or not template:
raise ValueError('Template must be a valid format string')
return template, outtype, annotation_classes
def infotodict(seqinfo):
"""Heuristic evaluator for determining which runs belong where
allowed template fields - follow python string module:
item: index within category
subject: participant id
seqitem: run number during scanning
subindex: sub index within group
session: session id (only for dataset_1)
"""
t1w1 = create_key('sub-{subject}/{session}/anat/sub-{subject}_{session}_T1w')
func_movie1 = create_key('sub-{subject}/{session}/func/sub-{subject}_{session}_task-movie_bold')
t1w = create_key('sub-{subject}/anat/sub-{subject}_T1w')
func_movie = create_key('sub-{subject}/func/sub-{subject}_task-movie_bold')
func_movie_echo_1 = create_key('sub-{subject}/func/sub-{subject}_task-movie_echo-1_bold')
func_movie_echo_2 = create_key('sub-{subject}/func/sub-{subject}_task-movie_echo-2_bold')
fmap_phase = create_key('sub-{subject}/fmap/sub-{subject}_phasediff')
fmap_magnitude = create_key('sub-{subject}/fmap/sub-{subject}_magnitude')
info = {t1w1: [], func_movie1: [], t1w: [], func_movie: [], fmap_phase: [], fmap_magnitude: [],
func_movie_echo_1: [], func_movie_echo_2: []}
for idx, s in enumerate(seqinfo):
if ('T1W_1mm_sag SENSE' in s.protocol_name):
info[t1w1].append(s.series_id)
if ('ToM_PartlyCloudy SENSE' in s.protocol_name):
info[func_movie1].append(s.series_id)
if ('t1_mpr_ns_sag_iso_ADNI_32ch' in s.protocol_name):
info[t1w].append(s.series_id)
if ('t1_mpr_ns_sag_P2_ADNI_32ch' in s.protocol_name):
info[t1w].append(s.series_id)
if (s.dim4 == 175) and ('FMRI_MB2_p2_2MMISO_TR2_movie' in s.protocol_name):
info[func_movie].append(s.series_id)
if (s.dim4 == 175) and ('FMRI_MB2_movie_p2_2MMISO_TR2' in s.protocol_name):
info[func_movie].append(s.series_id)
if (s.dim4 == 170) and ('ep2d_ToM_Loc' in s.protocol_name):
info[func_movie].append(s.series_id)
if (s.dim4 == 175) and ('ep2d_ToM_Loc' in s.protocol_name):
info[func_movie].append(s.series_id)
if (s.dim4 == 175) and ('ep2d_ToM_Loc_boldTR2' in s.protocol_name):
info[func_movie].append(s.series_id)
if (s.TE == 13) and ('BP_ep2d_multiecho_32ch_p3_TOM' in s.protocol_name):
info[func_movie_echo_1].append(s.series_id)
if (s.TE == 31.36) and ('BP_ep2d_multiecho_32ch_p3_TOM' in s.protocol_name):
info[func_movie_echo_2].append(s.series_id)
if (s.dim3 == 92) and ('gre_field_mapping_AAH' in s.protocol_name):
info[fmap_magnitude].append(s.series_id)
if (s.dim3 == 46) and ('gre_field_mapping_AAH' in s.protocol_name):
info[fmap_phase].append(s.series_id)
if (s.dim3 == 64) and ('gre_field_mapping_AAH' in s.protocol_name):
info[fmap_magnitude].append(s.series_id)
if (s.dim3 == 32) and ('gre_field_mapping_AAH' in s.protocol_name):
info[fmap_phase].append(s.series_id)
return info
Use the heuristic file to convert the Dicom files to .nii.gz (nifti) and create .json files:
docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_4/sourcedata/sub-{subject}/*.IMA -o /base/dataset_4 -f /base/code/heuristic_anthrom.py -s 401 -c dcm2niix -b --overwrite
For dataset_1 (for dataset_1 add ses-{session}/ and –ss 01 and .dcm). Movie for sub-101 and 102 is in ses-02:
docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1 -f /base/code/heuristic_anthrom.py -s 121 -ss 02 -c dcm2niix -b --overwrite
(Sub-116 was done manually in dcm2niigui): On the GRID Type in bash before running
Dataset_1:
singularity run -B /analyse/Project0255/:/base /analyse/Project0255/my_images/heudiconv_latest.sif -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1/ -f /base/code/heuristic_anthrom.py -s 116 -ss 01 -c dcm2niix -b --overwrite
Dataset_2 - 4:
singularity run -B /analyse/Project0255/:/base /analyse/Project0255/my_images/heudiconv_latest.sif -d /base/dataset_2/sourcedata/sub-{subject}/*.IMA -o /base/dataset_2/ -f /base/code/heuristic_anthrom.py -s 201 -c dcm2niix -b --overwrite
2.3 Anonymise the data
Deface using Pydeface:
#!/bin/bash
set -e
####For loop that defaces the MRI per subject and replaces the old MRI with the new defaced MRI
rootfolder=/Volumes/Project0255/dataset_4
for subj in 401; do
echo "Defacing participant $subj"
pydeface ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz
rm -f ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz
mv ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w_defaced.nii.gz ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz
done
For dataset_1: ses-01: 101 102 103 107 112 113 117 118 119 122 123 124 128 ses-02: 104 105 106 108 109 110 111 115 116 120 121 125 126 127
#!/bin/bash
set -e
rootfolder=/Volumes/Project0255/dataset_1
for subj in 129; do
echo "Defacing participant $subj"
for session in 01; do
for echo in 1 2 3 4 5; do
pydeface ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz
rm -f ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz
mv ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w_defaced.nii.gz ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz
done
done
done
2.4 Update the .json file for the fmaps for dataset_3 and dataset_4
You need to specify “IntendedFor” field in the _phasediff.json files to point which scans the estimated fieldmap should be applied to.
Run the following script (thanks to Michele Svanera for the code):
python change_json.py
2.5 Combine the dual-echo runs for dataset_4
Dataset_4 used dual-echo acquisition, we need to combine the two echos in order to be able to use fmriprep (see NeuroStar for more info). We created a dual_sum volume by adding the two images together (see Halai et al. 2014).
Run the following script (thanks to Tyler Morgan for the code):
python sum_echo.py
2.6 Theory-of-Mind event protocols
Create tsv file for functional localiser. Event coding (in s; 10s of fixation before movie starts; accounting for haemodynamic lag) is based on Richardson et al. 2018 - reverse correlation analyses.
Note: For sub-322 the trigger was at the start of the movie (thus create a different tsv, with event - 10s). Check the triggers for dataset_1.
PartlyCloudy <- data.frame(onset = c(86, 98, 120, 176, 238, 252, 300, 70, 92, 106, 136, 194, 210, 228, 262, 312), #create the events (same for every sub)
duration = c(4, 6, 4, 16, 6, 8, 6, 4, 2, 4, 10, 4, 12, 6, 6, 4),
trial_type = c(rep("mental",7), rep("pain",9)))
#dataset_1
for (sub in 102:129){ #note: localisers for sub-101 are in ses-02, see below
filename = paste("/Volumes/Project0255/dataset_1/sub-", sub, "/ses-01/func/sub-", sub, "_ses-01_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#write table for sub-101
write.table(PartlyCloudy, file = "/Volumes/Project0255/dataset_1/sub-101/ses-02/func/sub-101_ses-02_task-movie_events.tsv", sep="\t", row.names = FALSE, quote = FALSE)
#dataset_2
for (sub in 201:235){
filename = paste("/Volumes/Project0255/dataset_2/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#dataset_3
for (sub in 301:322){ #note: localisers for sub-322 should have t-10 (no trigger) <-manually correct this
filename = paste("/Volumes/Project0255/dataset_3/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#dataset_4
for (sub in 401:422){
filename = paste("/Volumes/Project0255/dataset_4/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
2.6 BIDS validation
Use the BIDS-Validator to check if the dataset is BIDS compliant:
docker run -ti --rm -v /Volumes/Project0255/dataset_4:/data:ro bids/validator /data
3. fMRI preprocessing
3.1 Run MRQIC
MRIQC is a docker tool to do quality control of the data. More info here.
MRIQC 0.14.2 was used:
docker run -it --rm -v /Volumes/Project0255/dataset_1/:/data:ro -v /Volumes/Project0255/dataset_1/derivatives/mriqc:/out poldracklab/mriqc:0.14.2 /data /out participant --participant-label 101 -m T1w bold --ica --fft-spikes-detector
On the GRID do (cd in /analyse folder):
singularity run --cleanenv /analyse/Project0255/my_images/mriqc-0.14.2.simg /analyse/Project0255/dataset_1 /analyse/Project0255/dataset_1/derivatives/mriqc participant --participant-label 123 -m T1w bold --ica --fft-spikes-detector -w /analyse/Project0255/work
Run it seperately for the datasets. Change participant to group to create the group reports:
docker run -it --rm -v /Volumes/Project0255/dataset_4/:/data:ro -v /Volumes/Project0255/dataset_4/derivatives/mriqc:/out poldracklab/mriqc:0.14.2 /data /out group
3.2 Compare MRIQC
Plot the output. This is based on MRIQCeption. The MRIQCeption Visualization by Catherine Walsh was adapted. Adjust the filter if you want to look at different measures.
Adjust this to your liking (e.g. bold: fd_mean, fd_perc, dvars_std, dvars_vstd, gcor, tsnr, t1w: cjv, cnr, snr, efc, inu, wm2max, fwhm) and modality (bold or t1w):
QCmeasure <- "fd_mean"
modality <- "bold"
Run the following code. Change the script below to load the group results for the different datasets:
#load data
DF.dataset1 <- read_tsv(file = paste("experiment1/dataset_1/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
gather("measure", "value", 2:46) %>%
select("bids_name","measure", "value")
Parsed with column specification:
cols(
.default = col_double(),
bids_name = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.dataset2 <- read_tsv(file = paste("experiment1/dataset_2/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
gather("measure", "value", 2:46) %>%
select("bids_name","measure", "value")
Parsed with column specification:
cols(
.default = col_double(),
bids_name = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.dataset3 <- read_tsv(file = paste("experiment1/dataset_3/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
gather("measure", "value", 2:46) %>%
select("bids_name","measure", "value")
Parsed with column specification:
cols(
.default = col_double(),
bids_name = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.dataset4 <- read_tsv(file = paste("experiment1/dataset_4/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
gather("measure", "value", 2:46) %>%
select("bids_name","measure", "value")
Parsed with column specification:
cols(
.default = col_double(),
bids_name = [31mcol_character()[39m
)
See spec(...) for full column specifications.
#select the most relevant measures
#selectionMeasure <- c("snr", "tsnr", "efc", "fber", "gsr_x", "gsr_y", "dvars_nstd", "dvars_std", "dvars_vstd", "gcor", "fd_mean", "fd_number", "fd_percentage", "spikes", "aor", "aqi")
#combine data
DF.full <- bind_rows(DF.dataset1, DF.dataset2, DF.dataset3, DF.dataset4, .id = "dataset") %>%
group_by(dataset) %>%
filter(measure == QCmeasure) #%in% c(selectionMeasure))
#create raincloud plot (check out the [github](https://github.com/RainCloudPlots/) or [preprint](https://wellcomeopenresearch.org/articles/4-63/v1)
p <- ggplot(DF.full,aes(x=dataset,y=value,fill=dataset))+
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 20)+
geom_boxplot(aes(x=dataset,y=value),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
#facet_wrap(. ~ dataset) +
theme_classic() + ylab(QCmeasure) + scale_fill_brewer(palette = "Reds") +
scale_colour_brewer(palette = "Reds") + ggtitle(paste("Comparison of", modality, "QC measure", QCmeasure, "between datasets")) +
facet_wrap(~measure)
p

3.3 fMRIprep
fMRIprep is a docker tool for preprocessing of the fMRI data. More info here
fMRIprep version 1.5.2 was used on a local iMac.
If you run into memory problems you can use –skip_bids_validation; skipped the –write-graph flag to save space, and –use-syn-sdc only for dataset_1 and datatset_2.
If run on the GRID, cd into the analyse folder and run:
singularity run --cleanenv /analyse/Project0255/my_images/fmriprep-1.5.2.simg /analyse/Project0255/dataset_1/ /analyse/Project0255/dataset_1/derivatives participant --participant-label sub-129 --fs-license-file /analyse/Project0255/my_images/license.txt --skip_bids_validation --use-syn-sd --fs-no-reconall -w /analyse/Project0255/work/compute00
Resize functional files for two participants (sub-117 and sub-125) from dataset_1 (sub-{sub}_ses-01_task-movie_space-MNI152NLin2009cAsym_desc-preproc_bold.nii) to allow for group comparison (run this in MATLAB):
voxsiz = [3 3 3.5]; % new voxel size {mm}
V = spm_select([1 Inf],'image');
V = spm_vol(V);
for i=1:numel(V)
bb = spm_get_bbox(V(i));
VV(1:2) = V(i);
VV(1).mat = spm_matrix([bb(1,:) 0 0 0 voxsiz])*spm_matrix([-1 -1 -1]);
VV(1).dim = ceil(VV(1).mat \ [bb(2,:) 1]' - 0.1)';
VV(1).dim = VV(1).dim(1:3);
spm_reslice(VV,struct('mean',false,'which',1,'interp',0)); % 1 for linear
end
4. fMRI analyses
4.1 Example script for first-level analysis
Example MATLAB script (dataset 3):
%========================================================================
% SPM first-level analysis for fmriprep data in BIDS format
%========================================================================
% This script is written by Ruud Hortensius and Michaela Kent
% (University of Glasgow). Based upon a script written by
% Shengdong Chen (ACRLAB) and Stephan Heunis (TU Eindhoven).
%
% Added: loop for runs
% Parameters as specified by Saxelab: https://saxelab.mit.edu/theory-mind-and-pain-matrix-localizer-movie-viewing-experiment
%
% Last updated: January 2020
%========================================================================
clear all
%% Inputdirs
BIDS = spm_BIDS('/Volumes/Project0255/dataset_3/'); % Parse BIDS directory (easier to query info from dataset)
BIDSpreproc=fullfile(BIDS.dir,'derivatives/fmriprep'); % get the preprocessed directory
%sublist = spm_BIDS(BIDS,'subjects') %number of subjects
sublist = transpose(BIDS.participants.participant_id) %get subject list including the 'sub'
subex = []
sublist(subex) = []; %update the subjects
taskid='movie'; %specify the task to be analysed
numScans=175; %The number of volumes per run <---
TR = 2; % Repetition time, in seconds <---
unit='secs'; % onset times in secs (seconds) or scans (TRs)
%% Outputdirs
outputdir=fullfile(BIDS.dir,'derivatives/bids_spm/first_level'); % root outputdir for sublist
spm_mkdir(outputdir,char(sublist), char(taskid)); % create output directory
%% Loop for sublist
spm('Defaults','fMRI'); %Initialise SPM fmri
spm_jobman('initcfg'); %Initialise SPM batch mode
for i=1:length(sublist)
%% Output dirs where you save SPM.mat
subdir=fullfile(outputdir,sublist{i},taskid);
%% Basic parameters
matlabbatch{1}.spm.stats.fmri_spec.dir = {subdir};
matlabbatch{1}.spm.stats.fmri_spec.timing.units = unit; % specified above
matlabbatch{1}.spm.stats.fmri_spec.timing.RT = TR; % specified above
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t = 68; %<--- look into this
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t0 = 34; %<--- look into this
%% Load input files for task specilized
sub_inputdir=fullfile(BIDSpreproc,sublist{i},'func');
sub_inputdirA=fullfile(BIDSpreproc,sublist{i},'anat');
%------------------------------------------------------------------
func=[sub_inputdir,filesep,sublist{i},'_task-',taskid,'_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'];
func_nii=[sub_inputdir,filesep,sublist{i}, '_task-',taskid,'_space-MNI152NLin2009cAsym_desc-preproc_bold.nii'];
if ~exist(func_nii,'file'), gunzip(func)
end
run_scans = spm_select('Expand',func_nii);
matlabbatch{1}.spm.stats.fmri_spec.sess(1).scans = cellstr(run_scans);
% Load the condition files
events = spm_load([BIDS.dir,filesep,sublist{i},'/func/', sublist{i},'_task-',taskid,'_events.tsv']) %load TSV condition file
names{1} = 'mental';
t = strcmp(names{1}, events.trial_type)
onsets{1} = transpose(events.onset(t));
durations{1} = transpose(events.duration(t));
names{2} = 'pain';
t = strcmp(names{2}, events.trial_type)
onsets{2} = transpose(events.onset(t));
durations{2} = transpose(events.duration(t));
file_mat = [subdir,filesep,sublist{i},'_task-',taskid,'_conditions.mat'];
save(file_mat, 'names', 'onsets', 'durations')
matlabbatch{1}.spm.stats.fmri_spec.sess(1).cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {}, 'orth', {});
matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi = {file_mat};
% Confounds file
confounds=spm_load([sub_inputdir,filesep,sublist{i},'_task-',taskid,'_desc-confounds_regressors.tsv']) ;
confounds_matrix=[confounds.framewise_displacement, confounds.a_comp_cor_00,confounds.a_comp_cor_01,confounds.a_comp_cor_02,confounds.a_comp_cor_03, confounds.a_comp_cor_04,confounds.a_comp_cor_05, confounds.trans_x, confounds.trans_y, confounds.trans_z, confounds.rot_x, confounds.rot_y, confounds.rot_z];
confounds_name=[subdir,filesep,sublist{i},'_task-',taskid,'_acomcorr.txt'];
confounds_matrix(isnan(confounds_matrix)) = 0 % nanmean(confounds_matrix); %check this <-----
if ~exist(confounds_name,'file'), dlmwrite(confounds_name,confounds_matrix)
end
matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi_reg = {confounds_name};
matlabbatch{1}.spm.stats.fmri_spec.sess(1).hpf = 128; % High-pass filter (hpf) without using consine
%% Model (Default)
matlabbatch{1}.spm.stats.fmri_spec.fact = struct('name', {}, 'levels', {});
matlabbatch{1}.spm.stats.fmri_spec.bases.hrf.derivs = [0 0];
matlabbatch{1}.spm.stats.fmri_spec.volt = 1;
matlabbatch{1}.spm.stats.fmri_spec.global = 'Scaling';
mask=[sub_inputdirA,filesep,sublist{i},'_space-MNI152NLin2009cAsym_label-GM_probseg.nii.gz'];
mask_nii=[sub_inputdirA,filesep,sublist{i},'_space-MNI152NLin2009cAsym_label-GM_probseg.nii'];
if ~exist(mask_nii,'file'), gunzip(mask)
end
mask_nii=[mask_nii, ',1']
matlabbatch{1}.spm.stats.fmri_spec.mask = {mask_nii};
matlabbatch{1}.spm.stats.fmri_spec.mthresh = 0.8;
matlabbatch{1}.spm.stats.fmri_spec.cvi = 'none';
%% Model estimation (Default)subdir
matlabbatch{2}.spm.stats.fmri_est.spmmat = {[subdir filesep 'SPM.mat']};
matlabbatch{2}.spm.stats.fmri_est.write_residuals = 0;
matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;
%% Contrasts
matlabbatch{3}.spm.stats.con.spmmat = {[subdir filesep 'SPM.mat']};
% Set contrasts of interest.
matlabbatch{3}.spm.stats.con.consess{1}.tcon.name = 'mental_pain';
matlabbatch{3}.spm.stats.con.consess{1}.tcon.convec = [1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0];
matlabbatch{3}.spm.stats.con.consess{2}.tcon.name = 'pain_mental';
matlabbatch{3}.spm.stats.con.consess{2}.tcon.convec = [-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0];
matlabbatch{3}.spm.stats.con.delete = 0;
%% Run matlabbatch jobs
spm_jobman('run',matlabbatch);
end
4.2 First-level analysis
Run the following commands in the terminal.
Dataset_1:
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1_ppn101"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1_ppn114"
Dataset_2:
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset2_ppn201_202"
Dataset_3:
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset3"
Dataset_4:
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset4"
4.3 Create group mask
Create a group average for the GM_probseg.nii for each dataset in Matlab (change the code per dataset; run this in MATLAB): ```{, eval = FALSE} clear all
spm(‘Defaults’,‘fMRI’); spm_jobman(‘initcfg’);
BIDS = spm_BIDS(‘/Volumes/Project0255/dataset_3’); %change this BIDSfirst=fullfile(BIDS.dir,‘derivatives/fmriprep’);
sublist = transpose(BIDS.participants.participant_id) subex = [] %subjects that don’t have an anatomical (14 dataset_1) sublist(subex) = [];
for i=1:length(sublist) subdir=fullfile(BIDSfirst,sublist{i}, ‘anat’) matlabbatch{1}.spm.util.imcalc.input{i,1} = [subdir, filesep, sublist{i}, ’_space-MNI152NLin2009cAsym_label-GM_probseg.nii,1’] end matlabbatch{1}.spm.util.imcalc.output = ‘dataset3_averageGM’; matlabbatch{1}.spm.util.imcalc.outdir = {‘/Volumes/Project0255/dataset_3/derivatives/fmriprep’}; %change this matlabbatch{1}.spm.util.imcalc.expression = ‘mean(X)’; matlabbatch{1}.spm.util.imcalc.var = struct(‘name’, {}, ‘value’, {}); matlabbatch{1}.spm.util.imcalc.options.dmtx = 1; matlabbatch{1}.spm.util.imcalc.options.mask = 0; matlabbatch{1}.spm.util.imcalc.options.interp = 1; matlabbatch{1}.spm.util.imcalc.options.dtype = 4;
spm_jobman(‘run’,matlabbatch); ```
4.4 Example script for second-level whole-brain analysis
Example MATLAB script (dataset 3): ```{, eval = FALSE} %======================================================================== % SPM second-level analysis for fmriprep data in BIDS format %======================================================================== % This script is written by Ruud Hortensius and Michaela Kent % (University of Glasgow) % % Last updated: January 2020 %========================================================================
clear all
%% Inputdirs BIDS = spm_BIDS(‘/Volumes/Project0255/dataset_3’); % Parse BIDS directory (easier to query info from dataset) BIDSfirst=fullfile(BIDS.dir,‘derivatives/bids_spm/first_level’); % get the first-level directory
sublist = transpose(BIDS.participants.participant_id) %get subject list including the ‘sub’ subex = [] %subjects that don’t have a second-session sublist(subex) = []; %update the subjects
%nsession = spm_BIDS(BIDS,‘sessions’) %how many sessions? careful, sometimes collapsing across sessions not wanted %sessionid = ‘ses-01’ %get session id
taskid=‘movieHC’; %specify the task to be analysed
contrast=‘con_0001’; %specify the contrast to be analysed contrast_name=‘mental_hc’; %specify the name of the contrast
smoothing = 1; %soomthing of first-level contrasts (1=yes, 0=no) s_kernel = [5 5 5]
%% Outputdirs outputdir=fullfile(BIDS.dir,‘derivatives/bids_spm/second_level’, char(contrast_name)); % root outputdir for sublist spm_mkdir(outputdir); % create output directory
spm(‘Defaults’,‘fMRI’); %Initialise SPM fmri spm_jobman(‘initcfg’); %Initialise SPM batch mode
%% Smoothing of first-level contrasts if smoothing == 1 for i=1:length(sublist) subdir=fullfile(BIDSfirst,sublist{i}, taskid); matlabbatch{1}.spm.spatial.smooth.data{i,1} = [subdir, filesep, contrast, ‘.nii,1’]; matlabbatch{1}.spm.spatial.smooth.fwhm = s_kernel; matlabbatch{1}.spm.spatial.smooth.dtype = 0; matlabbatch{1}.spm.spatial.smooth.im = 0; matlabbatch{1}.spm.spatial.smooth.prefix = ‘s’; end spm_jobman(‘run’,matlabbatch);
clear matlabbatch
end
%% Load the contrasts matlabbatch{1}.spm.stats.factorial_design.dir = {outputdir};
for i=1:length(sublist) subdir=fullfile(BIDSfirst,sublist{i}, taskid); if smoothing == 1 matlabbatch{1,1}.spm.stats.factorial_design.des.t1.scans{i,1} = [subdir, filesep, ‘s’, contrast, ‘.nii,1’] else matlabbatch{1,1}.spm.stats.factorial_design.des.t1.scans{i,1} = [subdir, filesep, contrast, ‘.nii,1’] end end
matlabbatch{1}.spm.stats.factorial_design.cov = struct(‘c’, {}, ‘cname’, {}, ‘iCFI’, {}, ‘iCC’, {}); matlabbatch{1}.spm.stats.factorial_design.multi_cov = struct(‘files’, {}, ‘iCFI’, {}, ‘iCC’, {}); matlabbatch{1}.spm.stats.factorial_design.masking.tm.tm_none = 1; matlabbatch{1}.spm.stats.factorial_design.masking.im = 1; matlabbatch{1}.spm.stats.factorial_design.masking.em = {’’}; matlabbatch{1}.spm.stats.factorial_design.globalc.g_omit = 1; matlabbatch{1}.spm.stats.factorial_design.globalm.gmsca.gmsca_no = 1; matlabbatch{1}.spm.stats.factorial_design.globalm.glonorm = 1;
%% Model estimation matlabbatch{2}.spm.stats.fmri_est.spmmat = {[outputdir filesep ‘SPM.mat’]}; matlabbatch{2}.spm.stats.fmri_est.write_residuals = 0; matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;
%% Contrast %————————————————————————– matlabbatch{3}.spm.stats.con.spmmat = {[outputdir filesep ‘SPM.mat’]}; matlabbatch{3}.spm.stats.con.consess{1}.tcon.name = contrast_name; matlabbatch{3}.spm.stats.con.consess{1}.tcon.weights = 1; matlabbatch{3}.spm.stats.con.consess{1}.tcon.sessrep = ‘none’; matlabbatch{3}.spm.stats.con.delete = 0;
%% Results %————————————————————————– matlabbatch{4}.spm.stats.results.spmmat = {[outputdir filesep ‘SPM.mat’]}; matlabbatch{4}.spm.stats.results.conspec.titlestr = ‘’; matlabbatch{4}.spm.stats.results.conspec.contrasts = 1; matlabbatch{4}.spm.stats.results.conspec.threshdesc = ’none’; matlabbatch{4}.spm.stats.results.conspec.thresh = 0.001; matlabbatch{4}.spm.stats.results.conspec.extent = 5; matlabbatch{4}.spm.stats.results.conspec.conjunction = 1; matlabbatch{4}.spm.stats.results.conspec.mask.image.name = {‘/Volumes/Project0255/dataset_3/derivatives/fmriprep/dataset3_averageGM.nii,1’}; matlabbatch{4}.spm.stats.results.conspec.mask.image.mtype = 0; matlabbatch{4}.spm.stats.results.units = 1; matlabbatch{4}.spm.stats.results.export{1}.pdf = true; matlabbatch{4}.spm.stats.results.export{2}.jpg = true; matlabbatch{4}.spm.stats.results.export{3}.csv = true; matlabbatch{4}.spm.stats.results.export{4}.tspm.basename = contrast_name;
%% Run matlabbatch jobs spm_jobman(‘run’,matlabbatch);
```
4.5 Second-level whole-brain analysis
Run it seperately for the datasets:
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset1"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset2"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset3"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset4"
4.6 ToM ROI analysis
Run the following (ROI_extract.m) script in matlab (change the code per dataset and roi and contrast - run this in MATLAB): ```{, eval = FALSE} %======================================================================== % ROI analysis for fmriprep data in BIDS format %======================================================================== % This script is written by Michaela Kent and Ruud Hortensius % (University of Glasgow) % % Last updated: January 2020 %======================================================================== clear all %add marsbar to path marsbar(‘on’)
%% Inputdirs BIDS = spm_BIDS(‘/Volumes/Project0255/dataset_4’); % parse BIDS directory (easier to query info from dataset) BIDSsecond=fullfile(BIDS.dir,‘derivatives/bids_spm/second_level’); % get the second-level directory
contrastid = ‘mental’ %can be either mental (vs. pain) or pain (vs. mental) networkid = ‘tom’ %can be either tom (theory-of-mind) or pain (pain matrix)
%% Outputdirs outputdir=fullfile(BIDS.dir,‘derivatives/roi’, networkid); % root outputdir for sublist spm_mkdir(outputdir); % create output directory
%% Load design matrix spm_name = spm_load(fullfile(BIDSsecond, filesep, contrastid , ‘SPM.mat’)) D = mardo(spm_name);
%% Load rois parcels = dir(fullfile(BIDS.dir,‘derivatives/parcels/’, networkid)) parcels = struct2cell(parcels(arrayfun(@(x) ~strcmp(x.name(1),‘.’),parcels))) parcels(2:6,:) = []
for i=1:length(parcels) roi = fullfile(BIDS.dir,‘derivatives/parcels/’, networkid, parcels{i}) R = maroi(roi); % Fetch data into marsbar data object mY = get_marsy(R, D, ‘mean’); roi_data = summary_data(mY); % get summary time course(s) roi_name = [outputdir,filesep,parcels{i},‘.tsv’]; dlmwrite(roi_name,roi_data); end ```
4.7 Custom steps
Add sub-201 and sub-202 to get the ROI data (different parameters, not included in the whole-brain analysis):
cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset2_201_202"
matlab -batch "ROI_extract_201_202"
5. IDAQ
5.1 Calculation of individual scores:
Dataset 2: sub-206-212, 219, 221-22, 224-25, 228, 231, 233-34 completed a version with the scale ranging from 1-10 instead of 0-10. Analyses should be run with and without these participants:
sub_ex = c(206:212, 219, 221:222, 224:225, 228, 231, 233:234)
Get the IDAQ data for all the participants:
#load data
DF.d1 <- read_csv(file = "experiment1/dataset_1/derivatives/IDAQ_dataset1.csv") %>%
gather("sub", "value", 4:32)
Parsed with column specification:
cols(
.default = col_double(),
scale = [31mcol_character()[39m,
subscale = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.d2 <- read_csv(file = "experiment1/dataset_2/derivatives/IDAQ_dataset2.csv") %>%
gather("sub", "value", 4:38)
Parsed with column specification:
cols(
.default = col_double(),
scale = [31mcol_character()[39m,
subscale = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.d3 <- read_csv(file = "experiment1/dataset_3/derivatives/IDAQ_dataset3.csv") %>%
gather("sub", "value", 4:25)
Parsed with column specification:
cols(
.default = col_double(),
scale = [31mcol_character()[39m,
subscale = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.d4 <- read_csv(file = "experiment1/dataset_4/derivatives/IDAQ_dataset4.csv") %>%
gather("sub", "value", 4:25)
Parsed with column specification:
cols(
.default = col_double(),
scale = [31mcol_character()[39m,
subscale = [31mcol_character()[39m
)
See spec(...) for full column specifications.
DF.idaq <- bind_rows(DF.d1, DF.d2, DF.d3, DF.d4, .id = "dataset") %>%
mutate(sub=gsub('sub-','',sub))%>%
transform(sub=as.integer(sub)) %>%
mutate(scale = as.factor(ifelse(scale == "IDAQ-NA", "IDAQNA", "IDAQ")))
rm(DF.d1, DF.d2, DF.d3, DF.d4)
5.2 Reliability of IDAQ
Check the reliability of the IDAQ scale:
DF.idaq %>%
filter(scale == "IDAQ") %>%
#filter(!sub %in% sub_ex) %>%
select(-scale, -subscale) %>%
spread(itemnr, value) %>%
select(-sub, -dataset) %>%
psych::alpha(na.rm = TRUE)
Reliability analysis
Call: psych::alpha(x = ., na.rm = TRUE)
lower alpha upper 95% confidence boundaries
0.75 0.8 0.86
Reliability if an item is dropped:
Item statistics
5.3 Reliability of IDAQ-NA
Check the reliability of the IDAQ-NA scale:
DF.idaq %>%
filter(scale == "IDAQNA") %>%
filter(!sub %in% sub_ex) %>%
select(-scale, -subscale) %>%
spread(itemnr, value) %>%
select(-sub, -dataset) %>%
psych::alpha(na.rm = TRUE)
Reliability analysis
Call: psych::alpha(x = ., na.rm = TRUE)
lower alpha upper 95% confidence boundaries
0.51 0.62 0.73
Reliability if an item is dropped:
Item statistics
5.4 IDAQ per subject
Calculate the IDAQ per subject:
DF.idaq <- DF.idaq %>%
dplyr::group_by(sub,dataset, scale) %>%
dplyr::summarise(score = sum(value, na.rm = TRUE)) %>%
ungroup()%>%
mutate_at(vars(-score),as.factor)
`summarise()` regrouping output by 'sub', 'dataset' (override with `.groups` argument)
5.5 Visualise the scores
Visualise the scores across the datasets and scales (Figure S1):
idaq_sum <- summarySEwithin(DF.idaq, measurevar="score", betweenvars="dataset", withinvars= "scale", idvar="sub")
FS1 <- DF.idaq %>%
group_by(sub,dataset, scale) %>%
ggplot(.,aes(x=dataset,y=score,fill=dataset, group = dataset))+
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .75, colour = "Black") +
geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
geom_boxplot(aes(x=dataset,y=score),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
geom_point(data = idaq_sum, aes(x = dataset, y = score), position = position_nudge(.3), colour = "BLACK")+
geom_errorbar(data = idaq_sum, aes(x=dataset,y=score, ymin = score-ci, ymax = score+ci), position=position_nudge(x = .3, y = 0), width = .05)+
scale_fill_brewer(palette = "Greys") +
scale_colour_brewer(palette = "Greys") +
ylab(paste("score (0-150)")) +
ggtitle(paste("IDAQ scores across datasets")) +
theme(legend.position="none") +
facet_wrap(~scale)
FS1
ggsave("experiment1/figures/S1.TIFF", plot = FS1, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Visualise the scores for IDAQ scale only (Figure 1A):
idaq_sum <- summarySEwithin(DF.idaq, measurevar="score", withinvars= "scale", idvar="sub")
F1A <- DF.idaq %>%
filter(scale == "IDAQ") %>%
group_by(sub) %>%
ggplot(.,aes(x = 1, y=score, fill = "Black"))+
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .75, colour = "Black") +
geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
geom_boxplot(aes(x=1,y=score),position=position_nudge(x = .12, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
geom_point(data = idaq_sum %>% filter(scale == "IDAQ"), aes(x = 0.95, y = score), position = position_nudge(.3), colour = "BLACK")+
geom_errorbar(data = idaq_sum %>% filter(scale == "IDAQ"), aes(x=0.95,y=score, ymin = score-ci, ymax = score+ci), position=position_nudge(x = .3, y = 0), width = .05)+
scale_fill_brewer(palette = "Greys") +
scale_colour_brewer(palette = "Greys") +
#theme_classic() +
coord_fixed(ratio = 1/90) +
ylab(paste("Dispositional anthropomorphism (0-150)")) +
#ggtitle(paste("Dispositional anthropomorphism")) +
theme(legend.position="none") +
theme(
axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank()
)
F1A
ggsave("experiment1/figures/F1A.TIFF", plot = F1A, width = 24.7, height = 15.24, units = "cm", dpi = 300)

6. ROI results
6.1 Data wrangling
Create function to load the data for the different networks:
roi_extract <- function(datasetno, substart, subend, network, nroi) {
dir_ls(paste("experiment1/dataset_", datasetno, "/derivatives/roi/", network, sep = ""), regexp = "\\.tsv$") %>%
map_dfr(read.delim, sep = "\t", .id = "id", header = FALSE) %>%
mutate(dataset = datasetno) %>%
mutate(network = network) %>%
mutate(network = str_extract(network, "tom|pain")) %>%
mutate(id = str_extract(id, "dmpfc|mmpfc|vmpfc|ltpj|rtpj|prec|amcc|lmfg|rmfg|ls2|rs2|linsula|rinsula")) %>%
dplyr::rename(roi = id, contrast = V1) %>%
mutate(sub = rep(substart:subend, times=nroi, each=1)) %>%
select(5,3,4,1:2)
}
Load the data for the Theory-of-Mind network:
DF.d1 <- roi_extract(1, 101, 129, "tom", 6)
DF.d2.a <- roi_extract(2, 201, 202, "tom/201_202", 6)
DF.d2.b <- roi_extract(2, 203, 235, "tom", 6)
DF.d3 <- roi_extract(3, 301, 322, "tom", 6)
DF.d4 <- roi_extract(4, 401, 422, "tom", 6)
DF.temp <- bind_rows(DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4)
Load the data for the Pain Matrix:
DF.d1 <- roi_extract(1, 101, 129, "pain", 7)
DF.d2.a <- roi_extract(2, 201, 202, "pain/201_202/", 7)
DF.d2.b <- roi_extract(2, 203, 235, "pain", 7)
DF.d3 <- roi_extract(3, 301, 322, "pain", 7)
DF.d4 <- roi_extract(4, 401, 422, "pain", 7)
DF.roi <- bind_rows(DF.temp, DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4)
rm(DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4, DF.temp)
Reorder ROI names for plots:
order <- c("rtpj", "ltpj", "prec", "vmpfc","mmpfc","dmpfc", "rs2", "ls2", "rinsula", "linsula", "rmfg", "lmfg", "amcc")
DF.roi <- DF.roi %>%
mutate_at(vars(-contrast),as.factor) %>%
group_by(sub, dataset) %>%
mutate(roi = fct_relevel(roi, order))
6.2 Theory-of-Mind network activation across datasets:
Plot the ToM activity across regions and datasets (Figure S2):
roi_sum <- summarySEwithin(DF.roi, measurevar="contrast", betweenvars="dataset", withinvars= c("roi","network"), idvar="sub")
FS2 <- DF.roi %>%
filter(network == "tom") %>%
ggplot(.,aes(x=roi,y=contrast,fill=roi))+
geom_hline(yintercept = 0, color = "grey", linetype = 2) +
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
geom_point(data = roi_sum %>% filter(network == "tom"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
geom_errorbar(data = roi_sum %>% filter(network == "tom"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
#theme_classic() +
ylab("Contrast estimates (mental > pain)") +
xlab("Region-of-interest") +
scale_fill_brewer(palette = "Blues") +
scale_colour_brewer(palette = "Blues") +
ggtitle(paste("Theory-of-Mind network contrasts estimates across datasets and regions")) +
theme(legend.position="none") +
facet_wrap(~dataset)
FS2
ggsave("experiment1/figures/S2.TIFF", plot = FS2, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Plot the ToM activity across regions (Figure 1C):
roi_sum <- summarySEwithin(DF.roi, measurevar="contrast", withinvars= c("roi","network"), idvar="sub")
F1C <- DF.roi %>%
filter(network == "tom") %>%
ggplot(.,aes(x=roi,y=contrast,fill=roi))+
geom_hline(yintercept = 0, color = "grey", linetype = 2) +
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
geom_point(data = roi_sum %>% filter(network == "tom"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
geom_errorbar(data = roi_sum %>% filter(network == "tom"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
#theme_classic() +
ylab("Theory-of-Mind network activation") +
xlab("Region-of-interest") +
scale_fill_brewer(palette = "Blues") +
scale_colour_brewer(palette = "Blues") +
#ggtitle(paste("Theory-of-Mind network contrasts estimates across datasets and regions")) +
theme(legend.position="none")
F1C
ggsave("experiment1/figures/F1C.TIFF", plot = F1C, width = 24.7, height = 15.24, units = "cm", dpi = 300)

6.3 Pain Matrix activation across datasets
Plot the Pain Matrix activity across regions and datasets (Figure S3):
FS3 <- DF.roi %>%
filter(network == "pain") %>%
ggplot(.,aes(x=roi,y=contrast,fill=roi))+
geom_hline(yintercept = 0, color = "grey", linetype = 2) +
geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
geom_point(data = roi_sum %>% filter(network == "pain"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
geom_errorbar(data = roi_sum %>% filter(network == "pain"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
#theme_classic() +
ylab("Contrast estimates (pain > mental)") +
xlab("Region-of-interest") +
scale_fill_brewer(palette = "Reds") +
scale_colour_brewer(palette = "Reds") +
ggtitle(paste("Pain Matrix contrasts estimates across datasets and regions")) +
theme(legend.position="none") +
facet_wrap(~dataset)
FS3
ggsave("experiment1/figures/S3.TIFF", plot = FS3, width = 24.7, height = 15.24, units = "cm", dpi = 300)

6.5 Combine IDAQ scores and ROI data:
Create one DF:
DF.roi <- DF.idaq %>%
group_by(sub,dataset, scale) %>%
ungroup() %>%
left_join(DF.roi, DF.idaq, by = c("sub","dataset"), keep = FALSE) %>%
pivot_wider(names_from=scale, values_from = score) #
Center the variables for the formal analysis:
DF.roi$cent_IDAQNA <- scale(DF.roi$IDAQNA, scale = TRUE)
DF.roi$cent_IDAQ <- scale(DF.roi$IDAQ, scale = TRUE)
DF.roi <- DF.roi %>% group_by(roi) %>% mutate(cent_contrast = scale(contrast, scale =TRUE)) #scale per roi (analyses are done per roi)
7. IDAQ scores and ToM activity
7.1 Plot ToM and IDAQ
Create scatterplots with linear and non-linear lines for ToM network:
F1D <- DF.roi %>%
filter(network == "tom") %>%
ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
geom_point(alpha=0.5,show.legend = FALSE) +
geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
coord_fixed(ratio = 1/1) +
labs(
x="Dispositional anthropomorphism",
y="Theory-of-Mind network activation"
) #+ theme_classic()
F1D
ggsave("experiment1/figures/F1D.TIFF", plot = F1D, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Create scatterplots with linear and non-linear lines for individual regions of ToM network:
theme_set(theme_classic(base_size = 7))
F1E <- DF.roi %>%
filter(network == "tom") %>%
ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
geom_point(alpha=0.5,show.legend = FALSE) +
geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
coord_fixed(ratio = 1/1) +
facet_wrap(~roi, ncol = 6) +
labs(
x="Dispositional anthropomorphism",
y="Contrast estimates"
) #+ theme_classic()
F1E
ggsave("experiment1/figures/F1E.TIFF", plot = F1E, width = 20, height = 6, units = "cm", dpi = 300)

7.2 Create a function for the Bayesian regression models:
For the formal analysis we will test a linear and quadratic relationship between IDAQ and ToM network activity:
DF.roi$cent_IDAQ2 <- DF.roi$cent_IDAQ^2
We run the models with uninformative (default) priors and create a function to run it for each region separately:
reg_model <- function(region){
brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
data = DF.roi %>% filter(roi == region),
family = gaussian,
chains = 4,
iter = 4000,
seed = 42, #so the model is reproducible
file = paste0("experiment1/models/regions/", region, ".RDS", sep = ""))
}
7.3 Run the ToM regression models:
Run the models for the ToM network first. It will load the model if it is already calculated:
rtpj <- reg_model("rtpj")
ltpj <- reg_model("ltpj")
prec <- reg_model("prec")
vmpfc <- reg_model("vmpfc")
mmpfc <- reg_model("mmpfc")
dmpfc <- reg_model("dmpfc")
Get the summaries (verbatim, run individually):
summary(rtpj)
summary(ltpj)
summary(prec)
summary(vmpfc)
summary(mmpfc)
summary(dmpfc)
7.4 ToM model output:
Use sjPlot to create html tables following procedure outlined here:
tab_model(
rtpj,ltpj,prec,vmpfc,mmpfc,dmpfc,
show.se = TRUE,
#collapse.se = TRUE,
pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
dv.labels = c("rtpj", "ltpj","prec","vmpfc","mmpfc","dmpfc"),
show.obs=FALSE
)
7.5 Posterior plots:
Create plots based on this tutorial:
tom_combined <- bind_rows("rtpj" = as_tibble(as.mcmc(rtpj, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE)),
"ltpj" = as_tibble(as.mcmc(ltpj, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"prec" = as_tibble(as.mcmc(prec, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"vmpfc" = as_tibble(as.mcmc(vmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"mmpfc" = as_tibble(as.mcmc(mmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"dmpfc" = as_tibble(as.mcmc(dmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
.id = "roi")
order <- c("rtpj", "ltpj", "prec", "vmpfc","mmpfc","dmpfc", "rs2", "ls2", "rinsula", "linsula", "rmfg", "lmfg", "amcc")
tom_combined <- tom_combined %>%
dplyr::rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
mutate(roi = fct_relevel(roi, order[1:6]))
Plot the distributions:
F2 <- tom_combined %>%
mutate_at(vars(-value),as.factor) %>%
dplyr::rename(predictor = varIDAQ) %>%
ggplot(., aes(value, fill = predictor)) +
geom_density(alpha = .5)+
geom_vline(xintercept = 0, color = "black", linetype = 2) +
ggtitle(paste("Posterior distributions for the Theory-of-Mind network")) +
facet_wrap(~roi, ncol =1) +
coord_fixed(ratio = 1/40) +
theme_classic(base_size = 8) +
theme(strip.background = element_blank()) +
scale_fill_manual(values=c("#0072B2", "#D55E00"))+
theme(axis.text.y = element_blank())
F2
ggsave("experiment1/figures/F2.TIFF", plot = F2, width = 24.7, height = 15.24, units = "cm", dpi = 300)

8. IDAQ scores and Pain Matrix activity
8.1 Plot Pain Matrix and IDAQ
Create scatterplots with linear and non-linear lines for the Pain Matrix:
S4 <- DF.roi %>%
filter(network == "pain") %>%
ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
geom_point(alpha=0.5,show.legend = FALSE) +
geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
#coord_fixed(ratio = 25/1) +
labs(
x="IDAQ score",
y="contrast (pain vs mental)"
) + theme_classic()
S4
ggsave("experiment1/figures/S4.TIFF", plot = S4, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Create scatterplots with linear and non-linear lines for individual regions of the Pain Matrix:
S5 <- DF.roi %>%
filter(network == "pain") %>%
ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
geom_point(alpha=0.5,show.legend = FALSE) +
geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
#coord_fixed(ratio = 25/1) +
labs(
x="IDAQ score",
y="contrast (pain vs mental)"
) + theme_classic() +
facet_wrap(~roi, nrow = 2)
S5
ggsave("experiment1/figures/S5.TIFF", plot = S5, width = 24.7, height = 15.24, units = "cm", dpi = 300)

8.2 Regression models for the Pain Matrix:
Run the models for the Pain Matrix (control network). It will load the model if it is already calculated:
rs2 <- reg_model("rs2")
ls2 <- reg_model("ls2")
rinsula <- reg_model("rinsula")
linsula <- reg_model("linsula")
rmfg <- reg_model("rmfg")
lmfg <- reg_model("lmfg")
amcc <- reg_model("amcc")
Get the summaries (verbatim, run individually):
summary(rs2)
summary(ls2)
summary(rinsula)
summary(linsula)
summary(rmfg)
summary(lmfg)
summary(amcc)
8.3 Pain Matrix model output:
Use sjPlot to create html tables following procedure outlined here:
tab_model(
rs2,ls2,rinsula,linsula,rmfg,lmfg,amcc,
show.se = TRUE,
#collapse.se = TRUE,
pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
dv.labels = c("rs2","ls2","rinsula","linsula","rmfg","lmfg","amcc"),
show.obs=FALSE
)
8.4 Posterior plots:
Create plots based on this tutorial:
pain_combined <- bind_rows("rs2" = as_tibble(as.mcmc(rs2, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE)),
"ls2" = as_tibble(as.mcmc(ls2, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"rinsula" = as_tibble(as.mcmc(rinsula, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"linsula" = as_tibble(as.mcmc(linsula, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"rmfg" = as_tibble(as.mcmc(rmfg, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"lmfg" = as_tibble(as.mcmc(lmfg, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
"amcc" = as_tibble(as.mcmc(amcc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
.id = "roi")
pain_combined <- pain_combined %>%
rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
mutate(roi = fct_relevel(roi, order[7:13]))
Error in rename(., linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) :
unused arguments (linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2)
Plot the distributions:
S6 <- pain_combined %>%
mutate_at(vars(-value),as.factor) %>%
dplyr::rename(predictor = varIDAQ) %>%
ggplot(., aes(value, fill = predictor)) +
geom_density(alpha = .5)+
geom_vline(xintercept = 0, color = "black", linetype = 2) +
ggtitle(paste("Posterior distributions for the Pain Matrix")) +
facet_wrap(~roi, ncol =1) +
coord_fixed(ratio = 1/40) +
theme_classic(base_size = 8) +
theme(strip.background = element_blank()) +
scale_fill_manual(values=c("#0072B2", "#D55E00"))
#theme(axis.text.y = element_blank())
S6
ggsave("experiment1/figures/S6.TIFF", plot = S6, width = 24.7, height = 15.24, units = "cm", dpi = 300)

9 One model across the networks
9.1 Theory-of-Mind:
All ToM regions combined:
tom <- brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
data = DF.roi %>% filter(network == "tom"),
family = gaussian,
chains = 4,
iter = 4000,
seed = 42, #so the model is reproducible
file = "experiment1/models/regions/tom.RDS")
Summary:
summary(tom)
Family: gaussian
Links: mu = identity; sigma = identity
Formula: cent_contrast ~ cent_IDAQ + cent_IDAQ2
Data: DF.roi %>% filter(network == "tom") (Number of observations: 648)
Samples: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
total post-warmup samples = 8000
Population-Level Effects:
Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept 0.05 0.05 -0.04 0.15 1.00 8563 6388
cent_IDAQ 0.04 0.04 -0.04 0.12 1.00 8235 5591
cent_IDAQ2 -0.05 0.03 -0.11 -0.00 1.00 8278 6444
Family Specific Parameters:
Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma 1.00 0.03 0.94 1.05 1.00 9276 5605
Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
9.2 Pain Matrix:
All pain matrix regions combined:
pain <- brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
data = DF.roi %>% filter(network == "pain"),
family = gaussian,
chains = 4,
iter = 4000,
seed = 42, #so the model is reproducible
file = "experiment1/models/regions/pain.RDS")
Summary:
summary(pain)
Family: gaussian
Links: mu = identity; sigma = identity
Formula: cent_contrast ~ cent_IDAQ + cent_IDAQ2
Data: DF.roi %>% filter(network == "pain") (Number of observations: 756)
Samples: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
total post-warmup samples = 8000
Population-Level Effects:
Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept -0.01 0.04 -0.10 0.08 1.00 8949 6471
cent_IDAQ 0.00 0.04 -0.07 0.07 1.00 8195 5869
cent_IDAQ2 0.01 0.03 -0.04 0.06 1.00 7997 6628
Family Specific Parameters:
Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma 1.00 0.03 0.95 1.05 1.00 7882 5243
Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
9.3 Posterior plots for the two networks:
tab_model(
tom, pain,
show.se = TRUE,
#collapse.se = TRUE,
pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
dv.labels = c("tom","pain"),
show.obs=FALSE
)
9.4 Posterior plots for the two networks:
tom_all <- bind_rows("all" = as_tibble(as.mcmc(tom, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE), .id = "network") %>%
dplyr::rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
mutate(network = "tom"))
pain_all <- bind_rows("all" = as_tibble(as.mcmc(pain, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE), .id = "network") %>%
dplyr::rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
mutate(network = "pain"))
tom_all %>% bind_rows(., pain_all) %>%
mutate_at(vars(-value),as.factor) %>%
dplyr::rename(predictor = varIDAQ) %>%
ggplot(., aes(value, fill = predictor)) +
geom_density(alpha = .5)+
geom_vline(xintercept = 0, color = "black", linetype = 2) +
ggtitle(paste("Posterior distributions across the two networks")) +
facet_wrap(~network) +
coord_fixed(ratio = 1/40) +
theme_classic(base_size = 16) +
scale_fill_manual(values=c("#0072B2", "#D55E00"))+
theme(strip.background = element_blank())

9.5 HDI+ROPE decision rule
hdi_rope <- function(model){
rope <- rope_range(model)
rope_model <- equivalence_test(model, range = rope, ci = 0.95)
#rope_model %>% mutate(roi = as.character(model$file))
plot(rope_model) + theme_classic() +
ggtitle(deparse(substitute(model))) +
xlim(-0.15,0.15) +
theme(axis.title.y = element_blank(), axis.title.x = element_blank())
#scale_fill_manual(values=c("#0072B2", "#D55E00"))
}
hdi_rope(tom) + hdi_rope(pain) + plot_layout(guides = 'collect')

(hdi_rope(rtpj) / hdi_rope(ltpj) / hdi_rope(prec)) &
(hdi_rope(vmpfc) / hdi_rope(mmpfc) / hdi_rope(dmpfc)) + plot_layout(guides = 'collect')

(hdi_rope(rtpj) | hdi_rope(ltpj)) /
(hdi_rope(prec) | hdi_rope(vmpfc)) /
(hdi_rope(mmpfc) | hdi_rope(dmpfc)) + plot_layout(guides = 'collect')

LS0tCnRpdGxlOiAiVGVzdGluZyB0aGUgcmVsYXRpb24gYmV0d2VlbiBkaXNwb3NpdGlvbmFsIGFudGhyb3BvbW9ycGhpc20gYW5kIFRoZW9yeS1vZi1NaW5kIG5ldHdvcmsgYWN0aXZhdGlvbiIKYXV0aG9yOiBSdXVkIEhvcnRlbnNpdXMgYW5kIE1pY2hhZWxhIEtlbnQKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBkZWZhdWx0CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMjIyMgUHJvamVjdCBBblRocm9NOiBleHBlcmltZW50IDEgCkp1bmUgMjAxOSAtIEp1bHkgMjAyMAoKIyAxLiBEZXRhaWxzIHsudGFic2V0fQoKIyMgMS4xIExpYnJhcmllcwpgYGB7ciwgbWVzc2FnZT1GQUxTRX0Kc291cmNlKCJSX3JhaW5jbG91ZHMuUiIpIApzb3VyY2UoInN1bW1hcnlTRS5SIikKbGlicmFyeShwc3ljaCkKbGlicmFyeShvcmRpbmFsKQpsaWJyYXJ5KGJybXMpCmxpYnJhcnkoZnMpCmxpYnJhcnkocGF0Y2h3b3JrKSAjZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ0aG9tYXNwODUvcGF0Y2h3b3JrIikKbGlicmFyeShlYXN5c3RhdHMpICNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImVhc3lzdGF0cy9lYXN5c3RhdHMiKQpsaWJyYXJ5KHNqUGxvdCkKbGlicmFyeShodHRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkodGlkeXZlcnNlKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNSkpIApvcHRpb25zKG1jLmNvcmVzID0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkpICNydW4gb24gbXVsdGlwbGUgY29yZXMpCm9wdGlvbnMoInNjaXBlbiI9MTAsICJkaWdpdHMiPTQpIApgYGAKCk5vdGU6IGZvciB0aGUgY29kZSBjaHVuayB0aGUgbGFuZ3VhZ2UgaXMgbGlzdGVkLCBidXQgYWxsIGV4Y2VwdCBmb3IgciBjaHVua3MgYXJlIGV4ZWN1dGVkIGluIHRoZSB0ZXJtaW5hbCAgIAoKIyMgMS4yIERhdGEgZGVzY3JpcHRpb24KCkRhdGEgb2YgdGhlIFRoZW9yeS1vZi1NaW5kIGZ1bmN0aW9uYWwgbG9jYWxpc2VyIGFuZCBJbmRpdmlkdWFsIERpZmZlcmVuY2VzIGluIEFudGhyb3BvbW9ycGhpc20gUXVlc3Rpb25uYWlyZSBhcmUgZnJvbSBmaXZlIGRpZmZlcmVudCBzdHVkaWVzLgogIAogRGF0YXNldF8xOiBCYW5nb3IgSW1hZ2luZyBVbml0OyBFTUJPVFM7ICpuKj0yOSAoaW5jbHVkaW5nIDEgcGlsb3Qgc2Nhbik7IGZ1bGwgZGF0YXNldCBhbmQgcHVibGljYXRpb246IFtDcm9zcy4uLkhvcnRlbnNpdXMgKDIwMTkpICAgUFRSQl0oaHR0cHM6Ly9yb3lhbHNvY2lldHlwdWJsaXNoaW5nLm9yZy9kb2kvMTAuMTA5OC9yc3RiLjIwMTguMDAzNCkuICAKIAogRGF0YXNldF8yOiBDZW50cmUgZm9yIENvZ25pdGl2ZSBOZXVyb0ltYWdpbmc7IFNIQVJFREJPVFM7ICpuKj0zNSAoaW5jbHVkaW5nIDIgcGlsb3Qgc2NhbnMpIHB1YmxpY2F0aW9uOiBIb3J0ZW5zaXVzICYgQ3Jvc3MsIGluIHByZXBhcmF0aW9uLiAgCiAKIERhdGFzZXRfMzogQ2VudHJlIGZvciBDb2duaXRpdmUgTmV1cm9JbWFnaW5nOyBUd28gc3R1ZGllcyB3aXRoIHRoZSBzYW1lIHBhcmFtZXRlcnM6ICpuKj0yMiAoaW5jbHVkaW5nIDIgcGlsb3Qgc2NhbnMpLiBTb2NpYWxfR3JhZGllbnRfMTsgKm4qPTEwIChwaWxvdCBleHBlcmltZW50KSBhbmQgQk9MRGxpZ2h0OyAqbio9MTIuICAKIAogRGF0YXNldF80OiBDZW50cmUgZm9yIENvZ25pdGl2ZSBOZXVyb0ltYWdpbmc7IEdBTUVCT1RTOyAqbio9MjIuICAKCkdldCBpbmZvIGZvciB0YWJsZSBTMToKYGBge3J9CiNsb2FkIGRhdGEKREYuZGF0YXNldDEgPC0gcmVhZF90c3YoZmlsZSA9ICJleHBlcmltZW50MS9kYXRhc2V0XzEvcGFydGljaXBhbnRzLnRzdiIpCkRGLmRhdGFzZXQyIDwtIHJlYWRfdHN2KGZpbGUgPSAiZXhwZXJpbWVudDEvZGF0YXNldF8yL3BhcnRpY2lwYW50cy50c3YiKQpERi5kYXRhc2V0MyA8LSByZWFkX3RzdihmaWxlID0gImV4cGVyaW1lbnQxL2RhdGFzZXRfMy9wYXJ0aWNpcGFudHMudHN2IikKREYuZGF0YXNldDQgPC0gcmVhZF90c3YoZmlsZSA9ICJleHBlcmltZW50MS9kYXRhc2V0XzQvcGFydGljaXBhbnRzLnRzdiIpCgojY29tYmluZSBkYXRhCmJpbmRfcm93cyhERi5kYXRhc2V0MSwgREYuZGF0YXNldDIsIERGLmRhdGFzZXQzLCAgREYuZGF0YXNldDQsIC5pZCA9ICJkYXRhc2V0IikgJT4lCiAgZ3JvdXBfYnkoZGF0YXNldCkgJT4lIAogIHN1bW1hcmlzZShtZWFuID0gbWVhbihhZ2UpLCAKICAgICAgICAgICAgc2QgPSBzZChhZ2UpKSAlPiUgCiAga25pdHI6OmthYmxlKC4sICJodG1sIiwgY2FwdGlvbiA9ICJBZ2UiKSAlPiUKICBrYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKCmJpbmRfcm93cyhERi5kYXRhc2V0MSwgREYuZGF0YXNldDIsIERGLmRhdGFzZXQzLCAgREYuZGF0YXNldDQsIC5pZCA9ICJkYXRhc2V0IikgJT4lCiAgZ3JvdXBfYnkoZGF0YXNldCwgc2V4KSAlPiUgCiAgdGFsbHkoKSAlPiUgCiAga25pdHI6OmthYmxlKC4sICJodG1sIiwgY2FwdGlvbiA9ICJTZXgiKSAlPiUKICBrYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKYGBgCgojIyAxLjMgTmV1cm9pbWFnaW5nIHByb2NlZHVyZQogCiBBbGwgcGFydGljaXBhbnRzIGNvbXBsZXRlZCBhIFRoZW9yeS1vZi1NaW5kIGxvY2FsaXNlciAoW0phY29ieSBldCBhbC4sIDIwMTZdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzEwNTM4MTE5MTUwMTA0NzIpOyBbUmljaGFyZHNvbiBldCBhbC4gMjAxOF0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE0NjctMDE4LTAzMzk5LTIpKSBhbmQgYW4gYW5hdG9taWNhbCBzY2FuIGVpdGhlciBpbiB0aGUgc2FtZSBzZXNzaW9uIG9yIGluIHR3byBzZXBlcmF0ZSBzZXNzaW9ucy4gRHVyaW5nIHRoZSBsb2NhbGlzZXIgcGFydGljaXBhbnRzIHBhc3NpdmVseSB2aWV3ZWQgYSBzaG9ydCA1LjYgbWluIGFuaW1hdGVkIGZpbG0gKFtQYXJ0bHkgQ2xvdWR5XShodHRwczovL3d3dy5waXhhci5jb20vcGFydGx5LWNsb3VkeSNwYXJ0bHktY2xvdWR5LTEpKS4gVGhpcyBtb3ZpZSBpbmNsdWRlcyBzY2VuZXMgZGVwaWN0aW5nIHBhaW4gKGUuZy4gYW4gYWxsaWdhdG9yIGJpdGluZyB0aGUgbWFpbiBjaGFyYWN0ZXIpIGFuZCBldmVudHMgdGhhdCB0cmlnZ2VyIG1lbnRhbGl6aW5nIChlLmcuIHRoZSBtYWluIGNoYXJhY3RlciByZXZlYWxpbmcgaXRzIGludGVudGlvbikuIEZvciBkYXRhc2V0XzMgYW5kIGRhdGFzZXRfNCBhIGZpZWxkbWFwIHdhcyBjb2xsZWN0ZWQgYXMgd2VsbC4gQXQgdGhlIGVuZCBvZiBlYWNoIGV4cGVyaW1lbnQgcGFydGljaXBhbnRzIGNvbXBsZXRlZCB0aGUgSW5kaXZpZHVhbCBEaWZmZXJlbmNlcyBpbiBBbnRocm9wb21vcnBoaXNtIFF1ZXN0aW9ubmFpcmUgKElEQVEpIChbV2F5dHogZXQgYWwuLCAyMDEwXShodHRwczovL2pvdXJuYWxzLnNhZ2VwdWIuY29tL2RvaS9mdWxsLzEwLjExNzcvMTc0NTY5MTYxMDM2OTMzNikpLiAKIAotIEJPTEQ6ICAgCiBEYXRhc2V0XzE6IDN4M3gzLjVtbSB2b3hlbHMsIDMyIHNsaWNlcywgcmVwZXRpdGlvbiB0aW1lID0gMnMsIGVjaG8gdGltZSA9IDMwbXMgIAogRGF0YXNldF8yOiAzbW0gaXNvdHJvcGljLCAzNyBzbGljZXMsIFRSID0gMnMsIFRFID0gMzBtcyAgCiBEYXRhc2V0XzM6IDJtbSBpc290cm9waWMsIDY4IHNsaWNlcywgVFIgPSAycywgVEUgPSAyNm1zICAKIERhdGFzZXRfNDogMi43NSB4IDIuNzUgeCA0bW0sIDMyIHNsaWNlcywgVFIgPSAycywgVEUgPSAxMyBhbmQgMzFtcyAgCiAKLSBUMVc6ICAgCiBEYXRhc2V0XzE6IDFtbSBpc290cm9waWMgcmVzb2x1dGlvbiwgVFIgPSAxMm1zLCBURSA9IDMuNDcgLyA1LjE1IC8gNi44MyAvIDguNTIgLyAxMC4yMG1zIChTRU5TRSkgIAogRGF0YXNldF8yIC0gNDogMW1tIGlzb3Ryb3BpYyByZXNvbHV0aW9uLCBUUiA9IDIuM3MsIFRFID0gMjkuNm1zIChBRE5JKSAgCiAKLSBGaWVsZG1hcHM6ICAgCiBEYXRhc2V0XzE6IG5vLCBzbyAtLXVzZS1zeW4tc2RjICAKIERhdGFzZXRfMjogbm8sIHNvIC0tdXNlLXN5bi1zZGMgIAogRGF0YXNldF8zOiB5ZXMgIAogRGF0YXNldF80OiB5ZXMgIAogCiMgMi4gQklEUyBkYXRhc2V0IHsudGFic2V0fQoKIyMgMi4xIENyZWF0aW5nIHRoZSBCSURTIGRhdGFzZXQKRm9yIHRoaXMgeW91IG5lZWQgSGV1RGlDb252IFtIZXVyaXN0aWMgRElDT00gQ29udmVydGVyXShodHRwczovL2dpdGh1Yi5jb20vbmlweS9oZXVkaWNvbnYpLiAgCkJhc2VkIG9uIHRoZSB0dXRvcmlhbCBieSBbRnJhbmtsaW4gRmVpbmdvbGRdKGh0dHA6Ly9yZXByb2R1Y2liaWxpdHkuc3RhbmZvcmQuZWR1L2JpZHMtdHV0b3JpYWwtc2VyaWVzLXBhcnQtMmEvKS4KCkRvd2xvYWQgdGhlIGxhdGVzdCB2ZXJzaW9uIG9mIEhldWRpY29udiAod2UgdXNlZCAwLjYuMC5kZXYxKToKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KZG9ja2VyIHB1bGwgbmlweS9oZXVkaWNvbnY6bGF0ZXN0CmBgYAoKSWYgb24gdGhlIEdSSUQgZG86CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CnNpbmd1bGFyaXR5IHB1bGwgZG9ja2VyOi8vbmlweS9oZXVkaWNvbnY6bGF0ZXN0CmBgYAoKQ3JlYXRlIHRoZSBpbmZvIGZpbGUgKGRhdGFzZXRfMiAtIDQpOgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpkb2NrZXIgcnVuIC0tcm0gLWl0IC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1LzovYmFzZSBuaXB5L2hldWRpY29udjpsYXRlc3QgLWQgL2Jhc2UvZGF0YXNldF8zL3NvdXJjZWRhdGEvc3ViLXtzdWJqZWN0fS8qLklNQSAtbyAvYmFzZS9kYXRhc2V0XzMgLWYgY29udmVydGFsbCAtcyAzMTUgLWMgbm9uZSAtLW92ZXJ3cml0ZQpgYGAKCkZvciBkYXRhc2V0XzEgd2UgZmlyc3QgbmVlZCB0byBjb252ZXJ0IHRoZSAuZGNtIGZyb20ganBlZy0yMDAwIGxvc3NsZXNzIHRvIHVuY29tcHJlc3NlZCBkY20gKHRoYW5rcyB0byBNaWNoZWxlIFN2YW5lcmEgZm9yIHRoZSBjb2RlKToKYGBge3B5dG9uLCBldmFsID0gRkFMU0V9CnB5dGhvbjMgY29udmVydF9hbGxfY29tcHJlc3NlZF9kaWNvbS5weQpgYGAKCkNyZWF0ZSB0aGUgaW5mbyBmaWxlIChkYXRhc2V0XzEpOgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpkb2NrZXIgcnVuIC0tcm0gLWl0IC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1LzovYmFzZSBuaXB5L2hldWRpY29udjpsYXRlc3QgLWQgL2Jhc2UvZGF0YXNldF8xL3NvdXJjZWRhdGEvc3ViLXtzdWJqZWN0fS9zZXMte3Nlc3Npb259LyouZGNtIC1vIC9iYXNlL2RhdGFzZXRfMSAtZiBjb252ZXJ0YWxsIC1zIDEyOSAtc3MgMDEgLWMgbm9uZSAtLW92ZXJ3cml0ZQpgYGAKCkdldCB0aGUgaW5mbyBmaWxlOgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpjcCAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLy5oZXVkaWNvbnYvMzAxL2luZm8vZGljb21pbmZvLnRzdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlCmBgYAoKIyMgMi4yIENyZWF0ZSB0aGUgaGV1cmlzdGljIGZpbGUKQ3JlYXRlIHRoZSBmb2xsb3dpbmcgcHl0aG9uIGZpbGUgYW5kIHNhdmUgaXQgaW4gdGhlIGNvZGUgZm9sZGVyLiBUaGVyZSBpcyBvbmUgZnVuY3Rpb25hbCB0YXNrIChmdW5jX21vdmllKSBhbmQgb25lIGFuYXRvbWljYWwgKHQxdykuIERhdGFzZXRfMyBhbmQgNCBoYXZlIGEgZmllbGQgbWFwIGFzIHdlbGwgKGZtYXBfcGhhc2UgYW5kIGZtYXBfbWFnbml0dWRlKSAKCkNyZWF0ZSBhIGhldXJpc3RpYyB0byBhdXRvbWF0aWNhbGx5IGNvbnZlcnQgdGhlIGZpbGVzOgpgYGB7cHl0aG9uLCBldmFsID0gRkFMU0V9CmltcG9ydCBvcwpkZWYgY3JlYXRlX2tleSh0ZW1wbGF0ZSwgb3V0dHlwZT0oJ25paS5neicsKSwgYW5ub3RhdGlvbl9jbGFzc2VzPU5vbmUpOgogICAgaWYgdGVtcGxhdGUgaXMgTm9uZSBvciBub3QgdGVtcGxhdGU6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignVGVtcGxhdGUgbXVzdCBiZSBhIHZhbGlkIGZvcm1hdCBzdHJpbmcnKQogICAgcmV0dXJuIHRlbXBsYXRlLCBvdXR0eXBlLCBhbm5vdGF0aW9uX2NsYXNzZXMKZGVmIGluZm90b2RpY3Qoc2VxaW5mbyk6CiAgICAiIiJIZXVyaXN0aWMgZXZhbHVhdG9yIGZvciBkZXRlcm1pbmluZyB3aGljaCBydW5zIGJlbG9uZyB3aGVyZQogICAgYWxsb3dlZCB0ZW1wbGF0ZSBmaWVsZHMgLSBmb2xsb3cgcHl0aG9uIHN0cmluZyBtb2R1bGU6CiAgICBpdGVtOiBpbmRleCB3aXRoaW4gY2F0ZWdvcnkKICAgIHN1YmplY3Q6IHBhcnRpY2lwYW50IGlkCiAgICBzZXFpdGVtOiBydW4gbnVtYmVyIGR1cmluZyBzY2FubmluZwogICAgc3ViaW5kZXg6IHN1YiBpbmRleCB3aXRoaW4gZ3JvdXAKICAgIHNlc3Npb246IHNlc3Npb24gaWQgKG9ubHkgZm9yIGRhdGFzZXRfMSkKICAgICIiIgogICAgCiAgICB0MXcxID0gY3JlYXRlX2tleSgnc3ViLXtzdWJqZWN0fS97c2Vzc2lvbn0vYW5hdC9zdWIte3N1YmplY3R9X3tzZXNzaW9ufV9UMXcnKQogICAgZnVuY19tb3ZpZTEgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L3tzZXNzaW9ufS9mdW5jL3N1Yi17c3ViamVjdH1fe3Nlc3Npb259X3Rhc2stbW92aWVfYm9sZCcpCgogICAgdDF3ID0gY3JlYXRlX2tleSgnc3ViLXtzdWJqZWN0fS9hbmF0L3N1Yi17c3ViamVjdH1fVDF3JykKICAgIGZ1bmNfbW92aWUgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2Z1bmMvc3ViLXtzdWJqZWN0fV90YXNrLW1vdmllX2JvbGQnKQogICAgZnVuY19tb3ZpZV9lY2hvXzEgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2Z1bmMvc3ViLXtzdWJqZWN0fV90YXNrLW1vdmllX2VjaG8tMV9ib2xkJykKICAgIGZ1bmNfbW92aWVfZWNob18yID0gY3JlYXRlX2tleSgnc3ViLXtzdWJqZWN0fS9mdW5jL3N1Yi17c3ViamVjdH1fdGFzay1tb3ZpZV9lY2hvLTJfYm9sZCcpCiAgICBmbWFwX3BoYXNlID0gY3JlYXRlX2tleSgnc3ViLXtzdWJqZWN0fS9mbWFwL3N1Yi17c3ViamVjdH1fcGhhc2VkaWZmJykKICAgIGZtYXBfbWFnbml0dWRlID0gY3JlYXRlX2tleSgnc3ViLXtzdWJqZWN0fS9mbWFwL3N1Yi17c3ViamVjdH1fbWFnbml0dWRlJykKICAgIAogICAgaW5mbyA9IHt0MXcxOiBbXSwgZnVuY19tb3ZpZTE6IFtdLCB0MXc6IFtdLCBmdW5jX21vdmllOiBbXSwgZm1hcF9waGFzZTogW10sIGZtYXBfbWFnbml0dWRlOiBbXSwKICAgICAgICAgICAgZnVuY19tb3ZpZV9lY2hvXzE6IFtdLCBmdW5jX21vdmllX2VjaG9fMjogW119IAogICAgCiAgICBmb3IgaWR4LCBzIGluIGVudW1lcmF0ZShzZXFpbmZvKToKICAgICAgICBpZiAoJ1QxV18xbW1fc2FnIFNFTlNFJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW3QxdzFdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAoJ1RvTV9QYXJ0bHlDbG91ZHkgU0VOU0UnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZnVuY19tb3ZpZTFdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAoJ3QxX21wcl9uc19zYWdfaXNvX0FETklfMzJjaCcgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1t0MXddLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAoJ3QxX21wcl9uc19zYWdfUDJfQUROSV8zMmNoJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW3Qxd10uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTQgPT0gMTc1KSBhbmQgKCdGTVJJX01CMl9wMl8yTU1JU09fVFIyX21vdmllJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2Z1bmNfbW92aWVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW00ID09IDE3NSkgYW5kICgnRk1SSV9NQjJfbW92aWVfcDJfMk1NSVNPX1RSMicgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltNCA9PSAxNzApIGFuZCAoJ2VwMmRfVG9NX0xvYycgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltNCA9PSAxNzUpIGFuZCAoJ2VwMmRfVG9NX0xvYycgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltNCA9PSAxNzUpIGFuZCAoJ2VwMmRfVG9NX0xvY19ib2xkVFIyJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2Z1bmNfbW92aWVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5URSA9PSAxMykgYW5kICgnQlBfZXAyZF9tdWx0aWVjaG9fMzJjaF9wM19UT00nIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZnVuY19tb3ZpZV9lY2hvXzFdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5URSA9PSAzMS4zNikgYW5kICgnQlBfZXAyZF9tdWx0aWVjaG9fMzJjaF9wM19UT00nIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZnVuY19tb3ZpZV9lY2hvXzJdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW0zID09IDkyKSBhbmQgKCdncmVfZmllbGRfbWFwcGluZ19BQUgnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZm1hcF9tYWduaXR1ZGVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW0zID09IDQ2KSBhbmQgKCdncmVfZmllbGRfbWFwcGluZ19BQUgnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZm1hcF9waGFzZV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTMgPT0gNjQpIGFuZCAoJ2dyZV9maWVsZF9tYXBwaW5nX0FBSCcgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmbWFwX21hZ25pdHVkZV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTMgPT0gMzIpIGFuZCAoJ2dyZV9maWVsZF9tYXBwaW5nX0FBSCcgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmbWFwX3BoYXNlXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICByZXR1cm4gaW5mbwpgYGAKClVzZSB0aGUgaGV1cmlzdGljIGZpbGUgdG8gY29udmVydCB0aGUgRGljb20gZmlsZXMgdG8gLm5paS5neiAobmlmdGkpIGFuZCBjcmVhdGUgLmpzb24gZmlsZXM6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmRvY2tlciBydW4gLS1ybSAtaXQgLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvOi9iYXNlIG5pcHkvaGV1ZGljb252OmxhdGVzdCAtZCAvYmFzZS9kYXRhc2V0XzQvc291cmNlZGF0YS9zdWIte3N1YmplY3R9LyouSU1BIC1vIC9iYXNlL2RhdGFzZXRfNCAtZiAvYmFzZS9jb2RlL2hldXJpc3RpY19hbnRocm9tLnB5IC1zIDQwMSAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCkZvciBkYXRhc2V0XzEgKGZvciBkYXRhc2V0XzEgYWRkIHNlcy17c2Vzc2lvbn0vIGFuZCAtLXNzIDAxIGFuZCAuZGNtKS4gTW92aWUgZm9yIHN1Yi0xMDEgYW5kIDEwMiBpcyBpbiBzZXMtMDI6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmRvY2tlciBydW4gLS1ybSAtaXQgLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvOi9iYXNlIG5pcHkvaGV1ZGljb252OmxhdGVzdCAtZCAvYmFzZS9kYXRhc2V0XzEvc291cmNlZGF0YS9zdWIte3N1YmplY3R9L3Nlcy17c2Vzc2lvbn0vKi5kY20gLW8gL2Jhc2UvZGF0YXNldF8xIC1mIC9iYXNlL2NvZGUvaGV1cmlzdGljX2FudGhyb20ucHkgLXMgMTIxIC1zcyAwMiAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCihTdWItMTE2IHdhcyBkb25lIG1hbnVhbGx5IGluIGRjbTJuaWlndWkpOiAKT24gdGhlIEdSSUQKVHlwZSBpbiBiYXNoIGJlZm9yZSBydW5uaW5nCgpEYXRhc2V0XzE6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CnNpbmd1bGFyaXR5IHJ1biAtQiAvYW5hbHlzZS9Qcm9qZWN0MDI1NS86L2Jhc2UgL2FuYWx5c2UvUHJvamVjdDAyNTUvbXlfaW1hZ2VzL2hldWRpY29udl9sYXRlc3Quc2lmIC1kIC9iYXNlL2RhdGFzZXRfMS9zb3VyY2VkYXRhL3N1Yi17c3ViamVjdH0vc2VzLXtzZXNzaW9ufS8qLmRjbSAtbyAvYmFzZS9kYXRhc2V0XzEvIC1mIC9iYXNlL2NvZGUvaGV1cmlzdGljX2FudGhyb20ucHkgLXMgMTE2IC1zcyAwMSAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCkRhdGFzZXRfMiAtIDQ6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CnNpbmd1bGFyaXR5IHJ1biAtQiAvYW5hbHlzZS9Qcm9qZWN0MDI1NS86L2Jhc2UgL2FuYWx5c2UvUHJvamVjdDAyNTUvbXlfaW1hZ2VzL2hldWRpY29udl9sYXRlc3Quc2lmIC1kIC9iYXNlL2RhdGFzZXRfMi9zb3VyY2VkYXRhL3N1Yi17c3ViamVjdH0vKi5JTUEgLW8gL2Jhc2UvZGF0YXNldF8yLyAtZiAvYmFzZS9jb2RlL2hldXJpc3RpY19hbnRocm9tLnB5IC1zIDIwMSAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCiMjIDIuMyBBbm9ueW1pc2UgdGhlIGRhdGEgCkRlZmFjZSB1c2luZyBbUHlkZWZhY2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9wb2xkcmFja2xhYi9weWRlZmFjZSk6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CiMhL2Jpbi9iYXNoCgpzZXQgLWUgCiMjIyNGb3IgbG9vcCB0aGF0IGRlZmFjZXMgdGhlIE1SSSBwZXIgc3ViamVjdCBhbmQgcmVwbGFjZXMgdGhlIG9sZCBNUkkgd2l0aCB0aGUgbmV3IGRlZmFjZWQgTVJJCnJvb3Rmb2xkZXI9L1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80Cgpmb3Igc3ViaiBpbiA0MDE7IGRvCgllY2hvICJEZWZhY2luZyBwYXJ0aWNpcGFudCAkc3ViaiIKcHlkZWZhY2UgJHtyb290Zm9sZGVyfS9zdWItJHtzdWJqfS9hbmF0L3N1Yi0ke3N1Ymp9X1Qxdy5uaWkuZ3oKcm0gLWYgJHtyb290Zm9sZGVyfS9zdWItJHtzdWJqfS9hbmF0L3N1Yi0ke3N1Ymp9X1Qxdy5uaWkuZ3oKbXYgJHtyb290Zm9sZGVyfS9zdWItJHtzdWJqfS9hbmF0L3N1Yi0ke3N1Ymp9X1Qxd19kZWZhY2VkLm5paS5neiAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L2FuYXQvc3ViLSR7c3Vian1fVDF3Lm5paS5neiAKZG9uZQpgYGAKCkZvciBkYXRhc2V0XzE6CnNlcy0wMTogMTAxIDEwMiAxMDMgMTA3IDExMiAxMTMgMTE3IDExOCAxMTkgMTIyIDEyMyAxMjQgMTI4CnNlcy0wMjogMTA0IDEwNSAxMDYgMTA4IDEwOSAxMTAgMTExIDExNSAxMTYgMTIwIDEyMSAxMjUgMTI2IDEyNwpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQojIS9iaW4vYmFzaAoKc2V0IC1lIApyb290Zm9sZGVyPS9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMQoKZm9yIHN1YmogaW4gMTI5OyBkbwoJZWNobyAiRGVmYWNpbmcgcGFydGljaXBhbnQgJHN1YmoiCmZvciBzZXNzaW9uIGluIDAxOyBkbwpmb3IgZWNobyBpbiAxIDIgMyA0IDU7IGRvCnB5ZGVmYWNlICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3Lm5paS5negpybSAtZiAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L3Nlcy0ke3Nlc3Npb259L2FuYXQvc3ViLSR7c3Vian1fc2VzLSR7c2Vzc2lvbn1fZWNoby0ke2VjaG99X1Qxdy5uaWkuZ3ogCm12ICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3X2RlZmFjZWQubmlpLmd6ICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3Lm5paS5neiAKZG9uZQpkb25lCmRvbmUKYGBgCgojIyAyLjQgVXBkYXRlIHRoZSAuanNvbiBmaWxlIGZvciB0aGUgZm1hcHMgZm9yIGRhdGFzZXRfMyBhbmQgZGF0YXNldF80CllvdSBuZWVkIHRvIHNwZWNpZnkg4oCcSW50ZW5kZWRGb3LigJ0gZmllbGQgaW4gdGhlIF9waGFzZWRpZmYuanNvbiBmaWxlcyB0byBwb2ludCB3aGljaCBzY2FucyB0aGUgZXN0aW1hdGVkIGZpZWxkbWFwIHNob3VsZCBiZSBhcHBsaWVkIHRvLgoKUnVuIHRoZSBmb2xsb3dpbmcgc2NyaXB0ICh0aGFua3MgdG8gTWljaGVsZSBTdmFuZXJhIGZvciB0aGUgY29kZSk6CmBgYHtweXRob24sIGV2YWwgPSBGQUxTRX0KcHl0aG9uIGNoYW5nZV9qc29uLnB5CmBgYAoKIyMgMi41IENvbWJpbmUgdGhlIGR1YWwtZWNobyBydW5zIGZvciBkYXRhc2V0XzQKRGF0YXNldF80IHVzZWQgZHVhbC1lY2hvIGFjcXVpc2l0aW9uLCB3ZSBuZWVkIHRvIGNvbWJpbmUgdGhlIHR3byBlY2hvcyBpbiBvcmRlciB0byBiZSBhYmxlIHRvIHVzZSBmbXJpcHJlcCAoc2VlIFtOZXVyb1N0YXJdKGh0dHBzOi8vbmV1cm9zdGFycy5vcmcvdC9mbXJpcHJlcC1kb2VzLW5vdC1jb21iaW5lLW11bHRpLWVjaG8tdGltZXNlcmllcy8zMzk4LzIpIGZvciBtb3JlIGluZm8pLiBXZSBjcmVhdGVkIGEgZHVhbF9zdW0gdm9sdW1lIGJ5IGFkZGluZyB0aGUgdHdvIGltYWdlcyB0b2dldGhlciAoc2VlIFtIYWxhaSBldCBhbC4gMjAxNF0oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvZnVsbC8xMC4xMDAyL2hibS4yMjQ2MykpLiAKClJ1biB0aGUgZm9sbG93aW5nIHNjcmlwdCAodGhhbmtzIHRvIFR5bGVyIE1vcmdhbiBmb3IgdGhlIGNvZGUpOgpgYGB7cHl0aG9uLCBldmFsID0gRkFMU0V9CnB5dGhvbiBzdW1fZWNoby5weQpgYGAKCiMjIDIuNiBUaGVvcnktb2YtTWluZCBldmVudCBwcm90b2NvbHMgCkNyZWF0ZSB0c3YgZmlsZSBmb3IgZnVuY3Rpb25hbCBsb2NhbGlzZXIuIEV2ZW50IGNvZGluZyAoaW4gczsgMTBzIG9mIGZpeGF0aW9uIGJlZm9yZSBtb3ZpZSBzdGFydHM7IGFjY291bnRpbmcgZm9yIGhhZW1vZHluYW1pYyBsYWcpIGlzIGJhc2VkIG9uIFJpY2hhcmRzb24gZXQgYWwuIDIwMTggLSByZXZlcnNlIGNvcnJlbGF0aW9uIGFuYWx5c2VzLiAKIApOb3RlOiBGb3Igc3ViLTMyMiB0aGUgdHJpZ2dlciB3YXMgYXQgdGhlIHN0YXJ0IG9mIHRoZSBtb3ZpZSAodGh1cyBjcmVhdGUgYSBkaWZmZXJlbnQgdHN2LCB3aXRoIGV2ZW50IC0gMTBzKS4KQ2hlY2sgdGhlIHRyaWdnZXJzIGZvciBkYXRhc2V0XzEuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpQYXJ0bHlDbG91ZHkgPC0gZGF0YS5mcmFtZShvbnNldCA9IGMoODYsIDk4LCAxMjAsIDE3NiwgMjM4LCAyNTIsIDMwMCwgNzAsIDkyLCAxMDYsIDEzNiwgMTk0LCAyMTAsIDIyOCwgMjYyLCAzMTIpLCAjY3JlYXRlIHRoZSBldmVudHMgKHNhbWUgZm9yIGV2ZXJ5IHN1YikKICAgICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb24gPSBjKDQsIDYsIDQsIDE2LCA2LCA4LCA2LCA0LCAyLCA0LCAxMCwgNCwgMTIsIDYsIDYsIDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmlhbF90eXBlID0gYyhyZXAoIm1lbnRhbCIsNyksIHJlcCgicGFpbiIsOSkpKQoKI2RhdGFzZXRfMQpmb3IgKHN1YiBpbiAxMDI6MTI5KXsgI25vdGU6IGxvY2FsaXNlcnMgZm9yIHN1Yi0xMDEgYXJlIGluIHNlcy0wMiwgc2VlIGJlbG93CiAgZmlsZW5hbWUgPSBwYXN0ZSgiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8xL3N1Yi0iLCBzdWIsICIvc2VzLTAxL2Z1bmMvc3ViLSIsIHN1YiwgIl9zZXMtMDFfdGFzay1tb3ZpZV9ldmVudHMudHN2Iiwgc2VwID0iIikKICB3cml0ZS50YWJsZShQYXJ0bHlDbG91ZHksIGZpbGUgPSBmaWxlbmFtZSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQp9Cgojd3JpdGUgdGFibGUgZm9yIHN1Yi0xMDEKd3JpdGUudGFibGUoUGFydGx5Q2xvdWR5LCBmaWxlID0gIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMS9zdWItMTAxL3Nlcy0wMi9mdW5jL3N1Yi0xMDFfc2VzLTAyX3Rhc2stbW92aWVfZXZlbnRzLnRzdiIsIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKCiNkYXRhc2V0XzIKZm9yIChzdWIgaW4gMjAxOjIzNSl7IAogIGZpbGVuYW1lID0gcGFzdGUoIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMi9zdWItIiwgc3ViLCAiL2Z1bmMvc3ViLSIsIHN1YiwgIl90YXNrLW1vdmllX2V2ZW50cy50c3YiLCBzZXAgPSIiKQogIHdyaXRlLnRhYmxlKFBhcnRseUNsb3VkeSwgZmlsZSA9IGZpbGVuYW1lLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCn0KI2RhdGFzZXRfMwpmb3IgKHN1YiBpbiAzMDE6MzIyKXsgI25vdGU6IGxvY2FsaXNlcnMgZm9yIHN1Yi0zMjIgc2hvdWxkIGhhdmUgdC0xMCAobm8gdHJpZ2dlcikgPC1tYW51YWxseSBjb3JyZWN0IHRoaXMKICBmaWxlbmFtZSA9IHBhc3RlKCIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvc3ViLSIsIHN1YiwgIi9mdW5jL3N1Yi0iLCBzdWIsICJfdGFzay1tb3ZpZV9ldmVudHMudHN2Iiwgc2VwID0iIikKICB3cml0ZS50YWJsZShQYXJ0bHlDbG91ZHksIGZpbGUgPSBmaWxlbmFtZSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQp9CiNkYXRhc2V0XzQKZm9yIChzdWIgaW4gNDAxOjQyMil7IAogIGZpbGVuYW1lID0gcGFzdGUoIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfNC9zdWItIiwgc3ViLCAiL2Z1bmMvc3ViLSIsIHN1YiwgIl90YXNrLW1vdmllX2V2ZW50cy50c3YiLCBzZXAgPSIiKQogIHdyaXRlLnRhYmxlKFBhcnRseUNsb3VkeSwgZmlsZSA9IGZpbGVuYW1lLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCn0KYGBgCgojIyAyLjYgQklEUyB2YWxpZGF0aW9uClVzZSB0aGUgQklEUy1WYWxpZGF0b3IgdG8gY2hlY2sgaWYgdGhlIGRhdGFzZXQgaXMgQklEUyBjb21wbGlhbnQ6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmRvY2tlciBydW4gLXRpIC0tcm0gLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80Oi9kYXRhOnJvIGJpZHMvdmFsaWRhdG9yIC9kYXRhCmBgYAoKIyAzLiBmTVJJIHByZXByb2Nlc3Npbmcgey50YWJzZXR9CgojIyAzLjEgUnVuIE1SUUlDCk1SSVFDIGlzIGEgZG9ja2VyIHRvb2wgdG8gZG8gcXVhbGl0eSBjb250cm9sIG9mIHRoZSBkYXRhLiBNb3JlIGluZm8gW2hlcmVdKGh0dHBzOi8vcG9sZHJhY2tsYWIuZ2l0aHViLmlvL21yaXFjLykuCgpNUklRQyAwLjE0LjIgd2FzIHVzZWQ6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmRvY2tlciBydW4gLWl0IC0tcm0gLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8xLzovZGF0YTpybyAtdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzEvZGVyaXZhdGl2ZXMvbXJpcWM6L291dCBwb2xkcmFja2xhYi9tcmlxYzowLjE0LjIgL2RhdGEgL291dCBwYXJ0aWNpcGFudCAtLXBhcnRpY2lwYW50LWxhYmVsIDEwMSAtbSBUMXcgYm9sZCAtLWljYSAtLWZmdC1zcGlrZXMtZGV0ZWN0b3IgCmBgYAoKT24gdGhlIEdSSUQgZG8gKGNkIGluIC9hbmFseXNlIGZvbGRlcik6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CnNpbmd1bGFyaXR5IHJ1biAtLWNsZWFuZW52IC9hbmFseXNlL1Byb2plY3QwMjU1L215X2ltYWdlcy9tcmlxYy0wLjE0LjIuc2ltZyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS9kYXRhc2V0XzEgL2FuYWx5c2UvUHJvamVjdDAyNTUvZGF0YXNldF8xL2Rlcml2YXRpdmVzL21yaXFjIHBhcnRpY2lwYW50IC0tcGFydGljaXBhbnQtbGFiZWwgMTIzIC1tIFQxdyBib2xkIC0taWNhIC0tZmZ0LXNwaWtlcy1kZXRlY3RvciAtdyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS93b3JrCmBgYAoKUnVuIGl0IHNlcGVyYXRlbHkgZm9yIHRoZSBkYXRhc2V0cy4gQ2hhbmdlIHBhcnRpY2lwYW50IHRvIGdyb3VwIHRvIGNyZWF0ZSB0aGUgZ3JvdXAgcmVwb3J0czoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KZG9ja2VyIHJ1biAtaXQgLS1ybSAtdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzQvOi9kYXRhOnJvIC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfNC9kZXJpdmF0aXZlcy9tcmlxYzovb3V0IHBvbGRyYWNrbGFiL21yaXFjOjAuMTQuMiAvZGF0YSAvb3V0IGdyb3VwCmBgYAoKIyMgMy4yIENvbXBhcmUgTVJJUUMKUGxvdCB0aGUgb3V0cHV0LiBUaGlzIGlzIGJhc2VkIG9uIFtNUklRQ2VwdGlvbl0oaHR0cHM6Ly9naXRodWIuY29tL2VsaXphYmV0aGJlYXJkL21yaXFjZXB0aW9uKS4gVGhlIE1SSVFDZXB0aW9uIFZpc3VhbGl6YXRpb24gYnkgQ2F0aGVyaW5lIFdhbHNoIHdhcyBhZGFwdGVkLiBBZGp1c3QgdGhlIGZpbHRlciBpZiB5b3Ugd2FudCB0byBsb29rIGF0IGRpZmZlcmVudCBtZWFzdXJlcy4KCkFkanVzdCB0aGlzIHRvIHlvdXIgbGlraW5nIChlLmcuIGJvbGQ6IGZkX21lYW4sIGZkX3BlcmMsIGR2YXJzX3N0ZCwgZHZhcnNfdnN0ZCwgZ2NvciwgdHNuciwgdDF3OiBjanYsIGNuciwgc25yLCBlZmMsIGludSwgd20ybWF4LCBmd2htKSBhbmQgbW9kYWxpdHkgKGJvbGQgb3IgdDF3KToKYGBge3J9ClFDbWVhc3VyZSA8LSAiZmRfbWVhbiIgCm1vZGFsaXR5IDwtICJib2xkIgpgYGAKClJ1biB0aGUgZm9sbG93aW5nIGNvZGUuIENoYW5nZSB0aGUgc2NyaXB0IGJlbG93IHRvIGxvYWQgdGhlIGdyb3VwIHJlc3VsdHMgZm9yIHRoZSBkaWZmZXJlbnQgZGF0YXNldHM6CmBgYHtyfQojbG9hZCBkYXRhCkRGLmRhdGFzZXQxICA8LSByZWFkX3RzdihmaWxlID0gcGFzdGUoImV4cGVyaW1lbnQxL2RhdGFzZXRfMS9kZXJpdmF0aXZlcy9tcmlxYy9ncm91cF8iLCBtb2RhbGl0eSwgIi50c3YiLCBzZXAgPSIiKSkgJT4lCiAgZ2F0aGVyKCJtZWFzdXJlIiwgInZhbHVlIiwgMjo0NikgJT4lCiAgc2VsZWN0KCJiaWRzX25hbWUiLCJtZWFzdXJlIiwgInZhbHVlIikKCkRGLmRhdGFzZXQyIDwtIHJlYWRfdHN2KGZpbGUgPSBwYXN0ZSgiZXhwZXJpbWVudDEvZGF0YXNldF8yL2Rlcml2YXRpdmVzL21yaXFjL2dyb3VwXyIsIG1vZGFsaXR5LCAiLnRzdiIsIHNlcCA9IiIpKSAlPiUKICBnYXRoZXIoIm1lYXN1cmUiLCAidmFsdWUiLCAyOjQ2KSAlPiUKICBzZWxlY3QoImJpZHNfbmFtZSIsIm1lYXN1cmUiLCAidmFsdWUiKQoKREYuZGF0YXNldDMgPC0gcmVhZF90c3YoZmlsZSA9IHBhc3RlKCJleHBlcmltZW50MS9kYXRhc2V0XzMvZGVyaXZhdGl2ZXMvbXJpcWMvZ3JvdXBfIiwgbW9kYWxpdHksICIudHN2Iiwgc2VwID0iIikpICU+JQogIGdhdGhlcigibWVhc3VyZSIsICJ2YWx1ZSIsIDI6NDYpICU+JQogIHNlbGVjdCgiYmlkc19uYW1lIiwibWVhc3VyZSIsICJ2YWx1ZSIpCgpERi5kYXRhc2V0NCA8LSByZWFkX3RzdihmaWxlID0gcGFzdGUoImV4cGVyaW1lbnQxL2RhdGFzZXRfNC9kZXJpdmF0aXZlcy9tcmlxYy9ncm91cF8iLCBtb2RhbGl0eSwgIi50c3YiLCBzZXAgPSIiKSkgJT4lCiAgZ2F0aGVyKCJtZWFzdXJlIiwgInZhbHVlIiwgMjo0NikgJT4lCiAgc2VsZWN0KCJiaWRzX25hbWUiLCJtZWFzdXJlIiwgInZhbHVlIikgCgojc2VsZWN0IHRoZSBtb3N0IHJlbGV2YW50IG1lYXN1cmVzCiNzZWxlY3Rpb25NZWFzdXJlIDwtIGMoInNuciIsICJ0c25yIiwgImVmYyIsICJmYmVyIiwgImdzcl94IiwgImdzcl95IiwgImR2YXJzX25zdGQiLCAiZHZhcnNfc3RkIiwgImR2YXJzX3ZzdGQiLCAiZ2NvciIsICJmZF9tZWFuIiwgImZkX251bWJlciIsICJmZF9wZXJjZW50YWdlIiwgInNwaWtlcyIsICJhb3IiLCAiYXFpIikKCiNjb21iaW5lIGRhdGEKREYuZnVsbCA8LSBiaW5kX3Jvd3MoREYuZGF0YXNldDEsIERGLmRhdGFzZXQyLCBERi5kYXRhc2V0MywgIERGLmRhdGFzZXQ0LCAuaWQgPSAiZGF0YXNldCIpICU+JQogIGdyb3VwX2J5KGRhdGFzZXQpICU+JSAKICBmaWx0ZXIobWVhc3VyZSA9PSBRQ21lYXN1cmUpICMlaW4lIGMoc2VsZWN0aW9uTWVhc3VyZSkpIAoKI2NyZWF0ZSByYWluY2xvdWQgcGxvdCAoY2hlY2sgb3V0IHRoZSBbZ2l0aHViXShodHRwczovL2dpdGh1Yi5jb20vUmFpbkNsb3VkUGxvdHMvKSBvciBbcHJlcHJpbnRdKGh0dHBzOi8vd2VsbGNvbWVvcGVucmVzZWFyY2gub3JnL2FydGljbGVzLzQtNjMvdjEpCnAgPC0gZ2dwbG90KERGLmZ1bGwsYWVzKHg9ZGF0YXNldCx5PXZhbHVlLGZpbGw9ZGF0YXNldCkpKwogIGdlb21fZmxhdF92aW9saW4ocG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4yLCB5ID0gMCksYWRqdXN0ID0yLCB0cmltID0gRkFMU0UsIGFscGhhID0gLjUsIGNvbG91ciA9IE5BKSsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkYXRhc2V0KSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoID0gLjA1KSwgc2l6ZSA9IC41LCBzaGFwZSA9IDIwKSsKICBnZW9tX2JveHBsb3QoYWVzKHg9ZGF0YXNldCx5PXZhbHVlKSxwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjEsIHkgPSAwKSxvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gLjUsIHdpZHRoID0gLjEsIGNvbG91ciA9ICJibGFjayIpKyAKICAjZmFjZXRfd3JhcCguIH4gZGF0YXNldCkgKwogIHRoZW1lX2NsYXNzaWMoKSArIHlsYWIoUUNtZWFzdXJlKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUmVkcyIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiUmVkcyIpICsgZ2d0aXRsZShwYXN0ZSgiQ29tcGFyaXNvbiBvZiIsIG1vZGFsaXR5LCAiUUMgbWVhc3VyZSIsIFFDbWVhc3VyZSwgImJldHdlZW4gZGF0YXNldHMiKSkgKwogIGZhY2V0X3dyYXAofm1lYXN1cmUpCnAKYGBgCgojIyAzLjMgZk1SSXByZXAgCmZNUklwcmVwIGlzIGEgZG9ja2VyIHRvb2wgZm9yIHByZXByb2Nlc3Npbmcgb2YgdGhlIGZNUkkgZGF0YS4gTW9yZSBpbmZvIFtoZXJlXShodHRwczovL2ZtcmlwcmVwLnJlYWR0aGVkb2NzLmlvL2VuL3N0YWJsZS8jKQoKZk1SSXByZXAgdmVyc2lvbiAxLjUuMiB3YXMgdXNlZCBvbiBhIGxvY2FsIGlNYWMuCgpJZiB5b3UgcnVuIGludG8gbWVtb3J5IHByb2JsZW1zIHlvdSBjYW4gdXNlIC0tc2tpcF9iaWRzX3ZhbGlkYXRpb247IHNraXBwZWQgdGhlIC0td3JpdGUtZ3JhcGggZmxhZyB0byBzYXZlIHNwYWNlLCBhbmQgLS11c2Utc3luLXNkYyBvbmx5IGZvciBkYXRhc2V0XzEgYW5kIGRhdGF0c2V0XzIuCgpJZiBydW4gb24gdGhlIEdSSUQsIGNkIGludG8gdGhlIGFuYWx5c2UgZm9sZGVyIGFuZCBydW46CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CnNpbmd1bGFyaXR5IHJ1biAtLWNsZWFuZW52IC9hbmFseXNlL1Byb2plY3QwMjU1L215X2ltYWdlcy9mbXJpcHJlcC0xLjUuMi5zaW1nIC9hbmFseXNlL1Byb2plY3QwMjU1L2RhdGFzZXRfMS8gL2FuYWx5c2UvUHJvamVjdDAyNTUvZGF0YXNldF8xL2Rlcml2YXRpdmVzIHBhcnRpY2lwYW50IC0tcGFydGljaXBhbnQtbGFiZWwgc3ViLTEyOSAtLWZzLWxpY2Vuc2UtZmlsZSAvYW5hbHlzZS9Qcm9qZWN0MDI1NS9teV9pbWFnZXMvbGljZW5zZS50eHQgLS1za2lwX2JpZHNfdmFsaWRhdGlvbiAtLXVzZS1zeW4tc2QgLS1mcy1uby1yZWNvbmFsbCAtdyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS93b3JrL2NvbXB1dGUwMApgYGAKClJlc2l6ZSBmdW5jdGlvbmFsIGZpbGVzIGZvciB0d28gcGFydGljaXBhbnRzIChzdWItMTE3IGFuZCBzdWItMTI1KSBmcm9tIGRhdGFzZXRfMSAoc3ViLXtzdWJ9X3Nlcy0wMV90YXNrLW1vdmllX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fZGVzYy1wcmVwcm9jX2JvbGQubmlpKSB0byBhbGxvdyBmb3IgZ3JvdXAgY29tcGFyaXNvbiAocnVuIHRoaXMgaW4gTUFUTEFCKToKYGBge30Kdm94c2l6ID0gWzMgMyAzLjVdOyAlIG5ldyB2b3hlbCBzaXplIHttbX0KViA9IHNwbV9zZWxlY3QoWzEgSW5mXSwnaW1hZ2UnKTsKViA9IHNwbV92b2woVik7CmZvciBpPTE6bnVtZWwoVikKICAgYmIgICAgICAgID0gc3BtX2dldF9iYm94KFYoaSkpOwogICBWVigxOjIpICAgPSBWKGkpOwogICBWVigxKS5tYXQgPSBzcG1fbWF0cml4KFtiYigxLDopIDAgMCAwIHZveHNpel0pKnNwbV9tYXRyaXgoWy0xIC0xIC0xXSk7CiAgIFZWKDEpLmRpbSA9IGNlaWwoVlYoMSkubWF0IFwgW2JiKDIsOikgMV0nIC0gMC4xKSc7CiAgIFZWKDEpLmRpbSA9IFZWKDEpLmRpbSgxOjMpOwogICBzcG1fcmVzbGljZShWVixzdHJ1Y3QoJ21lYW4nLGZhbHNlLCd3aGljaCcsMSwnaW50ZXJwJywwKSk7ICUgMSBmb3IgbGluZWFyCmVuZApgYGAKCiMgNC4gZk1SSSBhbmFseXNlcyB7LnRhYnNldH0KCiMjIDQuMSBFeGFtcGxlIHNjcmlwdCBmb3IgZmlyc3QtbGV2ZWwgYW5hbHlzaXMKRXhhbXBsZSBNQVRMQUIgc2NyaXB0IChkYXRhc2V0IDMpOgpgYGB7fQolPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiUgICAgIFNQTSBmaXJzdC1sZXZlbCBhbmFseXNpcyBmb3IgZm1yaXByZXAgZGF0YSBpbiBCSURTIGZvcm1hdAolPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiUgICAgIFRoaXMgc2NyaXB0IGlzIHdyaXR0ZW4gYnkgUnV1ZCBIb3J0ZW5zaXVzIGFuZCBNaWNoYWVsYSBLZW50CiUgICAgIChVbml2ZXJzaXR5IG9mIEdsYXNnb3cpLiBCYXNlZCB1cG9uIGEgc2NyaXB0IHdyaXR0ZW4gYnkgCiUgICAgIFNoZW5nZG9uZyBDaGVuIChBQ1JMQUIpIGFuZCBTdGVwaGFuIEhldW5pcyAoVFUgRWluZGhvdmVuKS4KJQolICAgICBBZGRlZDogbG9vcCBmb3IgcnVucwolICAgICBQYXJhbWV0ZXJzIGFzIHNwZWNpZmllZCBieSBTYXhlbGFiOiBodHRwczovL3NheGVsYWIubWl0LmVkdS90aGVvcnktbWluZC1hbmQtcGFpbi1tYXRyaXgtbG9jYWxpemVyLW1vdmllLXZpZXdpbmctZXhwZXJpbWVudAolCiUgICAgIExhc3QgdXBkYXRlZDogSmFudWFyeSAyMDIwCiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmNsZWFyIGFsbCAKCiUlIElucHV0ZGlycwpCSURTID0gc3BtX0JJRFMoJy9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMy8nKTsgJSBQYXJzZSBCSURTIGRpcmVjdG9yeSAoZWFzaWVyIHRvIHF1ZXJ5IGluZm8gZnJvbSBkYXRhc2V0KQpCSURTcHJlcHJvYz1mdWxsZmlsZShCSURTLmRpciwnZGVyaXZhdGl2ZXMvZm1yaXByZXAnKTsgJSBnZXQgdGhlIHByZXByb2Nlc3NlZCBkaXJlY3RvcnkKCiVzdWJsaXN0ID0gc3BtX0JJRFMoQklEUywnc3ViamVjdHMnKSAlbnVtYmVyIG9mIHN1YmplY3RzCnN1Ymxpc3QgPSB0cmFuc3Bvc2UoQklEUy5wYXJ0aWNpcGFudHMucGFydGljaXBhbnRfaWQpICVnZXQgc3ViamVjdCBsaXN0IGluY2x1ZGluZyB0aGUgJ3N1YicKc3ViZXggPSBbXSAKc3VibGlzdChzdWJleCkgPSBbXTsgJXVwZGF0ZSB0aGUgc3ViamVjdHMKCnRhc2tpZD0nbW92aWUnOyAlc3BlY2lmeSB0aGUgdGFzayB0byBiZSBhbmFseXNlZAoKbnVtU2NhbnM9MTc1OyAgJVRoZSBudW1iZXIgb2Ygdm9sdW1lcyBwZXIgcnVuIDwtLS0KClRSID0gMjsgICAgICUgUmVwZXRpdGlvbiB0aW1lLCBpbiBzZWNvbmRzIDwtLS0KdW5pdD0nc2Vjcyc7ICUgb25zZXQgdGltZXMgaW4gc2VjcyAoc2Vjb25kcykgb3Igc2NhbnMgKFRScykKCiUlIE91dHB1dGRpcnMKb3V0cHV0ZGlyPWZ1bGxmaWxlKEJJRFMuZGlyLCdkZXJpdmF0aXZlcy9iaWRzX3NwbS9maXJzdF9sZXZlbCcpOyAgJSByb290IG91dHB1dGRpciBmb3Igc3VibGlzdApzcG1fbWtkaXIob3V0cHV0ZGlyLGNoYXIoc3VibGlzdCksIGNoYXIodGFza2lkKSk7ICUgY3JlYXRlIG91dHB1dCBkaXJlY3RvcnkKCiUlIExvb3AgZm9yIHN1Ymxpc3QKc3BtKCdEZWZhdWx0cycsJ2ZNUkknKTsgJUluaXRpYWxpc2UgU1BNIGZtcmkKc3BtX2pvYm1hbignaW5pdGNmZycpOyAgJUluaXRpYWxpc2UgU1BNIGJhdGNoIG1vZGUKCmZvciBpPTE6bGVuZ3RoKHN1Ymxpc3QpCiAgICAKICAgIAogICAgJSUgT3V0cHV0IGRpcnMgd2hlcmUgeW91IHNhdmUgU1BNLm1hdAogICAgc3ViZGlyPWZ1bGxmaWxlKG91dHB1dGRpcixzdWJsaXN0e2l9LHRhc2tpZCk7CiAgICAKICAgICUlIEJhc2ljIHBhcmFtZXRlcnMKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuZGlyID0ge3N1YmRpcn07CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnRpbWluZy51bml0cyA9IHVuaXQ7ICUgc3BlY2lmaWVkIGFib3ZlCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnRpbWluZy5SVCA9IFRSOyAlIHNwZWNpZmllZCBhYm92ZQogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcuZm1yaV90ID0gNjg7ICU8LS0tIGxvb2sgaW50byB0aGlzCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnRpbWluZy5mbXJpX3QwID0gMzQ7ICU8LS0tIGxvb2sgaW50byB0aGlzCiAgICAKICAgICUlIExvYWQgaW5wdXQgZmlsZXMgZm9yIHRhc2sgc3BlY2lsaXplZAogICAgc3ViX2lucHV0ZGlyPWZ1bGxmaWxlKEJJRFNwcmVwcm9jLHN1Ymxpc3R7aX0sJ2Z1bmMnKTsKICAgIHN1Yl9pbnB1dGRpckE9ZnVsbGZpbGUoQklEU3ByZXByb2Msc3VibGlzdHtpfSwnYW5hdCcpOwogICAgCiAgICAlLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBmdW5jPVtzdWJfaW5wdXRkaXIsZmlsZXNlcCxzdWJsaXN0e2l9LCdfdGFzay0nLHRhc2tpZCwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fZGVzYy1wcmVwcm9jX2JvbGQubmlpLmd6J107CiAgICBmdW5jX25paT1bc3ViX2lucHV0ZGlyLGZpbGVzZXAsc3VibGlzdHtpfSwgJ190YXNrLScsdGFza2lkLCdfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9kZXNjLXByZXByb2NfYm9sZC5uaWknXTsKICAgIGlmIH5leGlzdChmdW5jX25paSwnZmlsZScpLCBndW56aXAoZnVuYykKICAgIGVuZAogICAgcnVuX3NjYW5zID0gc3BtX3NlbGVjdCgnRXhwYW5kJyxmdW5jX25paSk7CiAgICAKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuc2VzcygxKS5zY2FucyA9IGNlbGxzdHIocnVuX3NjYW5zKTsKICAgIAogICAgJSBMb2FkIHRoZSBjb25kaXRpb24gZmlsZXMKICAgIGV2ZW50cyA9IHNwbV9sb2FkKFtCSURTLmRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJy9mdW5jLycsIHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfZXZlbnRzLnRzdiddKSAlbG9hZCBUU1YgY29uZGl0aW9uIGZpbGUKICAgIAogICAgbmFtZXN7MX0gPSAnbWVudGFsJzsKICAgIHQgPSBzdHJjbXAobmFtZXN7MX0sIGV2ZW50cy50cmlhbF90eXBlKQogICAgb25zZXRzezF9ID0gdHJhbnNwb3NlKGV2ZW50cy5vbnNldCh0KSk7CiAgICBkdXJhdGlvbnN7MX0gPSB0cmFuc3Bvc2UoZXZlbnRzLmR1cmF0aW9uKHQpKTsKICAgIAogICAgbmFtZXN7Mn0gPSAncGFpbic7CiAgICB0ID0gc3RyY21wKG5hbWVzezJ9LCBldmVudHMudHJpYWxfdHlwZSkKICAgIG9uc2V0c3syfSA9IHRyYW5zcG9zZShldmVudHMub25zZXQodCkpOwogICAgZHVyYXRpb25zezJ9ID0gdHJhbnNwb3NlKGV2ZW50cy5kdXJhdGlvbih0KSk7CiAgICAKICAgIGZpbGVfbWF0ID0gW3N1YmRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfY29uZGl0aW9ucy5tYXQnXTsKICAgIHNhdmUoZmlsZV9tYXQsICduYW1lcycsICdvbnNldHMnLCAnZHVyYXRpb25zJykKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuc2VzcygxKS5jb25kID0gc3RydWN0KCduYW1lJywge30sICdvbnNldCcsIHt9LCAnZHVyYXRpb24nLCB7fSwgJ3Rtb2QnLCB7fSwgJ3Btb2QnLCB7fSwgJ29ydGgnLCB7fSk7CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MoMSkubXVsdGkgPSB7ZmlsZV9tYXR9OwogICAgCiAgICAlIENvbmZvdW5kcyBmaWxlCiAgICBjb25mb3VuZHM9c3BtX2xvYWQoW3N1Yl9pbnB1dGRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfZGVzYy1jb25mb3VuZHNfcmVncmVzc29ycy50c3YnXSkgIDsKICAgIGNvbmZvdW5kc19tYXRyaXg9W2NvbmZvdW5kcy5mcmFtZXdpc2VfZGlzcGxhY2VtZW50LCBjb25mb3VuZHMuYV9jb21wX2Nvcl8wMCxjb25mb3VuZHMuYV9jb21wX2Nvcl8wMSxjb25mb3VuZHMuYV9jb21wX2Nvcl8wMixjb25mb3VuZHMuYV9jb21wX2Nvcl8wMywgY29uZm91bmRzLmFfY29tcF9jb3JfMDQsY29uZm91bmRzLmFfY29tcF9jb3JfMDUsIGNvbmZvdW5kcy50cmFuc194LCBjb25mb3VuZHMudHJhbnNfeSwgY29uZm91bmRzLnRyYW5zX3osIGNvbmZvdW5kcy5yb3RfeCwgY29uZm91bmRzLnJvdF95LCBjb25mb3VuZHMucm90X3pdOwogICAgY29uZm91bmRzX25hbWU9W3N1YmRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfYWNvbWNvcnIudHh0J107CiAgICAKICAgIGNvbmZvdW5kc19tYXRyaXgoaXNuYW4oY29uZm91bmRzX21hdHJpeCkpID0gMCAlIG5hbm1lYW4oY29uZm91bmRzX21hdHJpeCk7ICVjaGVjayB0aGlzIDwtLS0tLQogICAgCiAgICBpZiB+ZXhpc3QoY29uZm91bmRzX25hbWUsJ2ZpbGUnKSwgZGxtd3JpdGUoY29uZm91bmRzX25hbWUsY29uZm91bmRzX21hdHJpeCkKICAgIGVuZAogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5zZXNzKDEpLm11bHRpX3JlZyA9IHtjb25mb3VuZHNfbmFtZX07CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MoMSkuaHBmID0gMTI4OyAlIEhpZ2gtcGFzcyBmaWx0ZXIgKGhwZikgd2l0aG91dCB1c2luZyBjb25zaW5lCiAgICAKICAgICUlIE1vZGVsICAoRGVmYXVsdCkKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuZmFjdCA9IHN0cnVjdCgnbmFtZScsIHt9LCAnbGV2ZWxzJywge30pOwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5iYXNlcy5ocmYuZGVyaXZzID0gWzAgMF07CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnZvbHQgPSAxOwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5nbG9iYWwgPSAnU2NhbGluZyc7CiAgICBtYXNrPVtzdWJfaW5wdXRkaXJBLGZpbGVzZXAsc3VibGlzdHtpfSwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fbGFiZWwtR01fcHJvYnNlZy5uaWkuZ3onXTsKICAgIG1hc2tfbmlpPVtzdWJfaW5wdXRkaXJBLGZpbGVzZXAsc3VibGlzdHtpfSwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fbGFiZWwtR01fcHJvYnNlZy5uaWknXTsKICAgIAogICAgaWYgfmV4aXN0KG1hc2tfbmlpLCdmaWxlJyksIGd1bnppcChtYXNrKQogICAgZW5kCiAgICBtYXNrX25paT1bbWFza19uaWksICcsMSddCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLm1hc2sgPSB7bWFza19uaWl9OwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5tdGhyZXNoID0gMC44OwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5jdmkgPSAnbm9uZSc7CiAgICAKICAgICUlIE1vZGVsIGVzdGltYXRpb24gKERlZmF1bHQpc3ViZGlyCiAgICBtYXRsYWJiYXRjaHsyfS5zcG0uc3RhdHMuZm1yaV9lc3Quc3BtbWF0ID0ge1tzdWJkaXIgZmlsZXNlcCAnU1BNLm1hdCddfTsKICAgIG1hdGxhYmJhdGNoezJ9LnNwbS5zdGF0cy5mbXJpX2VzdC53cml0ZV9yZXNpZHVhbHMgPSAwOwogICAgbWF0bGFiYmF0Y2h7Mn0uc3BtLnN0YXRzLmZtcmlfZXN0Lm1ldGhvZC5DbGFzc2ljYWwgPSAxOwogICAgCiAgICAlJSBDb250cmFzdHMKICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uc3BtbWF0ID0ge1tzdWJkaXIgZmlsZXNlcCAnU1BNLm1hdCddfTsKICAgICUgU2V0IGNvbnRyYXN0cyBvZiBpbnRlcmVzdC4KICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3sxfS50Y29uLm5hbWUgPSAnbWVudGFsX3BhaW4nOwogICAgbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5jb25zZXNzezF9LnRjb24uY29udmVjID0gWzEgLTEgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMF07CiAgICBtYXRsYWJiYXRjaHszfS5zcG0uc3RhdHMuY29uLmNvbnNlc3N7Mn0udGNvbi5uYW1lID0gJ3BhaW5fbWVudGFsJzsKICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3syfS50Y29uLmNvbnZlYyA9IFstMSAxIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDBdOwogICAgbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5kZWxldGUgPSAwOwogICAgCiAgICAlJSBSdW4gbWF0bGFiYmF0Y2ggam9icwogICAgc3BtX2pvYm1hbigncnVuJyxtYXRsYWJiYXRjaCk7CiAgICAKZW5kCmBgYAoKIyMgNC4yIEZpcnN0LWxldmVsIGFuYWx5c2lzIApSdW4gdGhlIGZvbGxvd2luZyBjb21tYW5kcyBpbiB0aGUgdGVybWluYWwuCgpEYXRhc2V0XzE6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDEiCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX2ZpcnN0bGV2ZWxfdG9tX2RhdGFzZXQxX3BwbjEwMSIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDFfcHBuMTE0IgpgYGAKCkRhdGFzZXRfMjoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KY2QgIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2NvZGUvIgptYXRsYWIgLWJhdGNoICJCSURTX1NQTV9maXJzdGxldmVsX3RvbV9kYXRhc2V0Ml9wcG4yMDFfMjAyIgpgYGAKCkRhdGFzZXRfMzoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KY2QgIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2NvZGUvIgptYXRsYWIgLWJhdGNoICJCSURTX1NQTV9maXJzdGxldmVsX3RvbV9kYXRhc2V0MyIKYGBgCgpEYXRhc2V0XzQ6CmBgYHtiYXNoLCBldmFsID0gRkFMU0V9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDQiCmBgYAoKIyMgNC4zIENyZWF0ZSBncm91cCBtYXNrCkNyZWF0ZSBhIGdyb3VwIGF2ZXJhZ2UgZm9yIHRoZSBHTV9wcm9ic2VnLm5paSBmb3IgZWFjaCBkYXRhc2V0IGluIE1hdGxhYiAoY2hhbmdlIHRoZSBjb2RlIHBlciBkYXRhc2V0OyBydW4gdGhpcyBpbiBNQVRMQUIpOgpgYGB7LCBldmFsID0gRkFMU0V9CmNsZWFyIGFsbAoKc3BtKCdEZWZhdWx0cycsJ2ZNUkknKTsKc3BtX2pvYm1hbignaW5pdGNmZycpOyAgCgpCSURTID0gc3BtX0JJRFMoJy9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMycpOyAlY2hhbmdlIHRoaXMKQklEU2ZpcnN0PWZ1bGxmaWxlKEJJRFMuZGlyLCdkZXJpdmF0aXZlcy9mbXJpcHJlcCcpOyAKCnN1Ymxpc3QgPSB0cmFuc3Bvc2UoQklEUy5wYXJ0aWNpcGFudHMucGFydGljaXBhbnRfaWQpIApzdWJleCA9IFtdICVzdWJqZWN0cyB0aGF0IGRvbid0IGhhdmUgYW4gYW5hdG9taWNhbCAoMTQgZGF0YXNldF8xKQpzdWJsaXN0KHN1YmV4KSA9IFtdOyAKCmZvciBpPTE6bGVuZ3RoKHN1Ymxpc3QpCiAgICBzdWJkaXI9ZnVsbGZpbGUoQklEU2ZpcnN0LHN1Ymxpc3R7aX0sICdhbmF0JykKICAgIG1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5pbnB1dHtpLDF9ID0gW3N1YmRpciwgZmlsZXNlcCwgc3VibGlzdHtpfSwgJ19zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX2xhYmVsLUdNX3Byb2JzZWcubmlpLDEnXQplbmQKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm91dHB1dCA9ICdkYXRhc2V0M19hdmVyYWdlR00nOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMub3V0ZGlyID0geycvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvZGVyaXZhdGl2ZXMvZm1yaXByZXAnfTsgJWNoYW5nZSB0aGlzCm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5leHByZXNzaW9uID0gJ21lYW4oWCknOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMudmFyID0gc3RydWN0KCduYW1lJywge30sICd2YWx1ZScsIHt9KTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm9wdGlvbnMuZG10eCA9IDE7Cm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5vcHRpb25zLm1hc2sgPSAwOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMub3B0aW9ucy5pbnRlcnAgPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMub3B0aW9ucy5kdHlwZSA9IDQ7CgpzcG1fam9ibWFuKCdydW4nLG1hdGxhYmJhdGNoKTsKYGBgCgojIyA0LjQgRXhhbXBsZSBzY3JpcHQgZm9yIHNlY29uZC1sZXZlbCB3aG9sZS1icmFpbiBhbmFseXNpcwpFeGFtcGxlIE1BVExBQiBzY3JpcHQgKGRhdGFzZXQgMyk6CmBgYHssIGV2YWwgPSBGQUxTRX0KJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQolICAgICBTUE0gc2Vjb25kLWxldmVsIGFuYWx5c2lzIGZvciBmbXJpcHJlcCBkYXRhIGluIEJJRFMgZm9ybWF0CiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KJSAgICAgVGhpcyBzY3JpcHQgaXMgd3JpdHRlbiBieSBSdXVkIEhvcnRlbnNpdXMgYW5kIE1pY2hhZWxhIEtlbnQgCiUgICAgIChVbml2ZXJzaXR5IG9mIEdsYXNnb3cpIAolCiUgICAgIExhc3QgdXBkYXRlZDogSmFudWFyeSAyMDIwCiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCgpjbGVhciBhbGwKCiUlIElucHV0ZGlycwpCSURTID0gc3BtX0JJRFMoJy9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMycpOyAlIFBhcnNlIEJJRFMgZGlyZWN0b3J5IChlYXNpZXIgdG8gcXVlcnkgaW5mbyBmcm9tIGRhdGFzZXQpCkJJRFNmaXJzdD1mdWxsZmlsZShCSURTLmRpciwnZGVyaXZhdGl2ZXMvYmlkc19zcG0vZmlyc3RfbGV2ZWwnKTsgJSBnZXQgdGhlIGZpcnN0LWxldmVsIGRpcmVjdG9yeQoKc3VibGlzdCA9IHRyYW5zcG9zZShCSURTLnBhcnRpY2lwYW50cy5wYXJ0aWNpcGFudF9pZCkgJWdldCBzdWJqZWN0IGxpc3QgaW5jbHVkaW5nIHRoZSAnc3ViJwpzdWJleCA9IFtdICVzdWJqZWN0cyB0aGF0IGRvbid0IGhhdmUgYSBzZWNvbmQtc2Vzc2lvbgpzdWJsaXN0KHN1YmV4KSA9IFtdOyAldXBkYXRlIHRoZSBzdWJqZWN0cwoKJW5zZXNzaW9uID0gc3BtX0JJRFMoQklEUywnc2Vzc2lvbnMnKSAlaG93IG1hbnkgc2Vzc2lvbnM/IGNhcmVmdWwsIHNvbWV0aW1lcyBjb2xsYXBzaW5nIGFjcm9zcyBzZXNzaW9ucyBub3Qgd2FudGVkCiVzZXNzaW9uaWQgPSAnc2VzLTAxJyAlZ2V0IHNlc3Npb24gaWQKCnRhc2tpZD0nbW92aWVIQyc7ICVzcGVjaWZ5IHRoZSB0YXNrIHRvIGJlIGFuYWx5c2VkCgpjb250cmFzdD0nY29uXzAwMDEnOyAlc3BlY2lmeSB0aGUgY29udHJhc3QgdG8gYmUgYW5hbHlzZWQKY29udHJhc3RfbmFtZT0nbWVudGFsX2hjJzsgJXNwZWNpZnkgdGhlIG5hbWUgb2YgdGhlIGNvbnRyYXN0CgpzbW9vdGhpbmcgPSAxOyAlc29vbXRoaW5nIG9mIGZpcnN0LWxldmVsIGNvbnRyYXN0cyAoMT15ZXMsIDA9bm8pCnNfa2VybmVsID0gWzUgNSA1XQoKJSUgT3V0cHV0ZGlycwpvdXRwdXRkaXI9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL2JpZHNfc3BtL3NlY29uZF9sZXZlbCcsIGNoYXIoY29udHJhc3RfbmFtZSkpOyAgJSByb290IG91dHB1dGRpciBmb3Igc3VibGlzdApzcG1fbWtkaXIob3V0cHV0ZGlyKTsgJSBjcmVhdGUgb3V0cHV0IGRpcmVjdG9yeSAKCnNwbSgnRGVmYXVsdHMnLCdmTVJJJyk7ICVJbml0aWFsaXNlIFNQTSBmbXJpCnNwbV9qb2JtYW4oJ2luaXRjZmcnKTsgICVJbml0aWFsaXNlIFNQTSBiYXRjaCBtb2RlCgoKJSUgU21vb3RoaW5nIG9mIGZpcnN0LWxldmVsIGNvbnRyYXN0cwppZiBzbW9vdGhpbmcgPT0gMQogICAgZm9yIGk9MTpsZW5ndGgoc3VibGlzdCkKICAgICAgICBzdWJkaXI9ZnVsbGZpbGUoQklEU2ZpcnN0LHN1Ymxpc3R7aX0sIHRhc2tpZCk7CiAgICAgICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLmRhdGF7aSwxfSA9IFtzdWJkaXIsIGZpbGVzZXAsIGNvbnRyYXN0LCAnLm5paSwxJ107CiAgICAgICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLmZ3aG0gPSBzX2tlcm5lbDsKICAgICAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGguZHR5cGUgPSAwOwogICAgICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zcGF0aWFsLnNtb290aC5pbSA9IDA7CiAgICAgICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLnByZWZpeCA9ICdzJzsKICAgIGVuZAogICAgc3BtX2pvYm1hbigncnVuJyxtYXRsYWJiYXRjaCk7CiAgICAKICAgIGNsZWFyIG1hdGxhYmJhdGNoCmVuZAoKCiUlIExvYWQgdGhlIGNvbnRyYXN0cwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5kaXIgPSB7b3V0cHV0ZGlyfTsKCmZvciBpPTE6bGVuZ3RoKHN1Ymxpc3QpCiAgICBzdWJkaXI9ZnVsbGZpbGUoQklEU2ZpcnN0LHN1Ymxpc3R7aX0sIHRhc2tpZCk7CiAgICBpZiBzbW9vdGhpbmcgPT0gMQogICAgICAgIG1hdGxhYmJhdGNoezEsMX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24uZGVzLnQxLnNjYW5ze2ksMX0gPSBbc3ViZGlyLCBmaWxlc2VwLCAncycsIGNvbnRyYXN0LCAnLm5paSwxJ10KICAgIGVsc2UKICAgICAgICBtYXRsYWJiYXRjaHsxLDF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLmRlcy50MS5zY2Fuc3tpLDF9ID0gW3N1YmRpciwgZmlsZXNlcCwgY29udHJhc3QsICcubmlpLDEnXQogICAgZW5kCmVuZAoKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24uY292ID0gc3RydWN0KCdjJywge30sICdjbmFtZScsIHt9LCAnaUNGSScsIHt9LCAnaUNDJywge30pOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5tdWx0aV9jb3YgPSBzdHJ1Y3QoJ2ZpbGVzJywge30sICdpQ0ZJJywge30sICdpQ0MnLCB7fSk7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLm1hc2tpbmcudG0udG1fbm9uZSA9IDE7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLm1hc2tpbmcuaW0gPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5tYXNraW5nLmVtID0geycnfTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24uZ2xvYmFsYy5nX29taXQgPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5nbG9iYWxtLmdtc2NhLmdtc2NhX25vID0gMTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24uZ2xvYmFsbS5nbG9ub3JtID0gMTsKCiUlIE1vZGVsIGVzdGltYXRpb24gCm1hdGxhYmJhdGNoezJ9LnNwbS5zdGF0cy5mbXJpX2VzdC5zcG1tYXQgPSB7W291dHB1dGRpciBmaWxlc2VwICdTUE0ubWF0J119OwptYXRsYWJiYXRjaHsyfS5zcG0uc3RhdHMuZm1yaV9lc3Qud3JpdGVfcmVzaWR1YWxzID0gMDsKbWF0bGFiYmF0Y2h7Mn0uc3BtLnN0YXRzLmZtcmlfZXN0Lm1ldGhvZC5DbGFzc2ljYWwgPSAxOwoKJSUgQ29udHJhc3QKJS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uc3BtbWF0ID0ge1tvdXRwdXRkaXIgZmlsZXNlcCAnU1BNLm1hdCddfTsKbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5jb25zZXNzezF9LnRjb24ubmFtZSA9IGNvbnRyYXN0X25hbWU7Cm1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3sxfS50Y29uLndlaWdodHMgPSAxOwptYXRsYWJiYXRjaHszfS5zcG0uc3RhdHMuY29uLmNvbnNlc3N7MX0udGNvbi5zZXNzcmVwID0gJ25vbmUnOwptYXRsYWJiYXRjaHszfS5zcG0uc3RhdHMuY29uLmRlbGV0ZSA9IDA7CgolJSBSZXN1bHRzCiUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5zcG1tYXQgPSB7W291dHB1dGRpciBmaWxlc2VwICdTUE0ubWF0J119OwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLnRpdGxlc3RyID0gJyc7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMuY29udHJhc3RzID0gMTsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuY29uc3BlYy50aHJlc2hkZXNjID0gJ25vbmUnOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLnRocmVzaCA9IDAuMDAxOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLmV4dGVudCA9IDU7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMuY29uanVuY3Rpb24gPSAxOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLm1hc2suaW1hZ2UubmFtZSA9IHsnL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8zL2Rlcml2YXRpdmVzL2ZtcmlwcmVwL2RhdGFzZXQzX2F2ZXJhZ2VHTS5uaWksMSd9OwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLm1hc2suaW1hZ2UubXR5cGUgPSAwOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy51bml0cyA9IDE7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmV4cG9ydHsxfS5wZGYgPSB0cnVlOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5leHBvcnR7Mn0uanBnID0gdHJ1ZTsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuZXhwb3J0ezN9LmNzdiA9IHRydWU7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmV4cG9ydHs0fS50c3BtLmJhc2VuYW1lID0gY29udHJhc3RfbmFtZTsKCiUlIFJ1biBtYXRsYWJiYXRjaCBqb2JzCnNwbV9qb2JtYW4oJ3J1bicsbWF0bGFiYmF0Y2gpOwoKYGBgCgojIyA0LjUgU2Vjb25kLWxldmVsIHdob2xlLWJyYWluIGFuYWx5c2lzIApSdW4gaXQgc2VwZXJhdGVseSBmb3IgdGhlIGRhdGFzZXRzOgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpjZCAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZS8iCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX3NlY29uZGxldmVsX3RvbV9kYXRhc2V0MSIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fc2Vjb25kbGV2ZWxfdG9tX2RhdGFzZXQyIgptYXRsYWIgLWJhdGNoICJCSURTX1NQTV9zZWNvbmRsZXZlbF90b21fZGF0YXNldDMiCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX3NlY29uZGxldmVsX3RvbV9kYXRhc2V0NCIKYGBgCgojIyA0LjYgVG9NIFJPSSBhbmFseXNpcyAgClJ1biB0aGUgZm9sbG93aW5nIChST0lfZXh0cmFjdC5tKSBzY3JpcHQgaW4gbWF0bGFiIChjaGFuZ2UgdGhlIGNvZGUgcGVyIGRhdGFzZXQgYW5kIHJvaSBhbmQgY29udHJhc3QgLSBydW4gdGhpcyBpbiBNQVRMQUIpOgpgYGB7LCBldmFsID0gRkFMU0V9CiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KJSAgICAgUk9JIGFuYWx5c2lzIGZvciBmbXJpcHJlcCBkYXRhIGluIEJJRFMgZm9ybWF0CiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KJSAgICAgVGhpcyBzY3JpcHQgaXMgd3JpdHRlbiBieSAgTWljaGFlbGEgS2VudCBhbmQgUnV1ZCBIb3J0ZW5zaXVzCiUgICAgIChVbml2ZXJzaXR5IG9mIEdsYXNnb3cpIAolCiUgICAgIExhc3QgdXBkYXRlZDogSmFudWFyeSAyMDIwCiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2xlYXIgYWxsCiVhZGQgbWFyc2JhciB0byBwYXRoCm1hcnNiYXIoJ29uJykKCiUlIElucHV0ZGlycwpCSURTID0gc3BtX0JJRFMoJy9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfNCcpOyAlIHBhcnNlIEJJRFMgZGlyZWN0b3J5IChlYXNpZXIgdG8gcXVlcnkgaW5mbyBmcm9tIGRhdGFzZXQpCkJJRFNzZWNvbmQ9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL2JpZHNfc3BtL3NlY29uZF9sZXZlbCcpOyAlIGdldCB0aGUgc2Vjb25kLWxldmVsIGRpcmVjdG9yeQoKY29udHJhc3RpZCA9ICdtZW50YWwnICVjYW4gYmUgZWl0aGVyIG1lbnRhbCAodnMuIHBhaW4pIG9yIHBhaW4gKHZzLiBtZW50YWwpCm5ldHdvcmtpZCA9ICd0b20nICVjYW4gYmUgZWl0aGVyIHRvbSAodGhlb3J5LW9mLW1pbmQpIG9yIHBhaW4gKHBhaW4gbWF0cml4KQoKJSUgT3V0cHV0ZGlycwpvdXRwdXRkaXI9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL3JvaScsIG5ldHdvcmtpZCk7ICAlIHJvb3Qgb3V0cHV0ZGlyIGZvciBzdWJsaXN0CnNwbV9ta2RpcihvdXRwdXRkaXIpOyAlIGNyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5IAoKJSUgTG9hZCBkZXNpZ24gbWF0cml4CnNwbV9uYW1lID0gc3BtX2xvYWQoZnVsbGZpbGUoQklEU3NlY29uZCwgZmlsZXNlcCwgY29udHJhc3RpZCAsICdTUE0ubWF0JykpCkQgID0gbWFyZG8oc3BtX25hbWUpOwoKCiUlIExvYWQgcm9pcwpwYXJjZWxzID0gZGlyKGZ1bGxmaWxlKEJJRFMuZGlyLCdkZXJpdmF0aXZlcy9wYXJjZWxzLycsIG5ldHdvcmtpZCkpCnBhcmNlbHMgPSBzdHJ1Y3QyY2VsbChwYXJjZWxzKGFycmF5ZnVuKEAoeCkgfnN0cmNtcCh4Lm5hbWUoMSksJy4nKSxwYXJjZWxzKSkpCnBhcmNlbHMoMjo2LDopID0gW10KCmZvciBpPTE6bGVuZ3RoKHBhcmNlbHMpIAogICAgcm9pID0gZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL3BhcmNlbHMvJywgIG5ldHdvcmtpZCwgcGFyY2Vsc3tpfSkKICAgIFIgID0gbWFyb2kocm9pKTsKICAgICUgRmV0Y2ggZGF0YSBpbnRvIG1hcnNiYXIgZGF0YSBvYmplY3QKICAgIG1ZICA9IGdldF9tYXJzeShSLCBELCAnbWVhbicpOwogICAgcm9pX2RhdGEgPSBzdW1tYXJ5X2RhdGEobVkpOyAlIGdldCBzdW1tYXJ5IHRpbWUgY291cnNlKHMpCiAgICByb2lfbmFtZSA9IFtvdXRwdXRkaXIsZmlsZXNlcCxwYXJjZWxze2l9LCcudHN2J107CiAgICBkbG13cml0ZShyb2lfbmFtZSxyb2lfZGF0YSk7CmVuZApgYGAKCiMjIDQuNyBDdXN0b20gc3RlcHMKQWRkIHN1Yi0yMDEgYW5kIHN1Yi0yMDIgdG8gZ2V0IHRoZSBST0kgZGF0YSAoZGlmZmVyZW50IHBhcmFtZXRlcnMsIG5vdCBpbmNsdWRlZCBpbiB0aGUgd2hvbGUtYnJhaW4gYW5hbHlzaXMpOgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpjZCAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZS8iCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX3NlY29uZGxldmVsX3RvbV9kYXRhc2V0Ml8yMDFfMjAyIgptYXRsYWIgLWJhdGNoICJST0lfZXh0cmFjdF8yMDFfMjAyIgpgYGAKCiMgNS4gSURBUSB7LnRhYnNldH0KCiMjIDUuMSBDYWxjdWxhdGlvbiBvZiBpbmRpdmlkdWFsIHNjb3JlczoKRGF0YXNldCAyOiBzdWItMjA2LTIxMiwgMjE5LCAyMjEtMjIsIDIyNC0yNSwgMjI4LCAyMzEsIDIzMy0zNCBjb21wbGV0ZWQgYSB2ZXJzaW9uIHdpdGggdGhlIHNjYWxlIHJhbmdpbmcgZnJvbSAxLTEwIGluc3RlYWQgb2YgMC0xMC4gQW5hbHlzZXMgc2hvdWxkIGJlIHJ1biB3aXRoIGFuZCB3aXRob3V0IHRoZXNlIHBhcnRpY2lwYW50czoKYGBge3J9CnN1Yl9leCA9IGMoMjA2OjIxMiwgMjE5LCAyMjE6MjIyLCAyMjQ6MjI1LCAyMjgsIDIzMSwgMjMzOjIzNCkKYGBgCgpHZXQgdGhlIElEQVEgZGF0YSBmb3IgYWxsIHRoZSBwYXJ0aWNpcGFudHM6CmBgYHtyfQojbG9hZCBkYXRhIApERi5kMSAgPC0gcmVhZF9jc3YoZmlsZSA9ICJleHBlcmltZW50MS9kYXRhc2V0XzEvZGVyaXZhdGl2ZXMvSURBUV9kYXRhc2V0MS5jc3YiKSAlPiUKICBnYXRoZXIoInN1YiIsICJ2YWx1ZSIsIDQ6MzIpCgpERi5kMiAgPC0gcmVhZF9jc3YoZmlsZSA9ICJleHBlcmltZW50MS9kYXRhc2V0XzIvZGVyaXZhdGl2ZXMvSURBUV9kYXRhc2V0Mi5jc3YiKSAlPiUKICBnYXRoZXIoInN1YiIsICJ2YWx1ZSIsIDQ6MzgpIAoKREYuZDMgIDwtIHJlYWRfY3N2KGZpbGUgPSAiZXhwZXJpbWVudDEvZGF0YXNldF8zL2Rlcml2YXRpdmVzL0lEQVFfZGF0YXNldDMuY3N2IikgJT4lCiAgZ2F0aGVyKCJzdWIiLCAidmFsdWUiLCA0OjI1KSAKCkRGLmQ0ICA8LSByZWFkX2NzdihmaWxlID0gImV4cGVyaW1lbnQxL2RhdGFzZXRfNC9kZXJpdmF0aXZlcy9JREFRX2RhdGFzZXQ0LmNzdiIpICU+JQogIGdhdGhlcigic3ViIiwgInZhbHVlIiwgNDoyNSkgCgpERi5pZGFxIDwtIGJpbmRfcm93cyhERi5kMSwgREYuZDIsIERGLmQzLCBERi5kNCwgLmlkID0gImRhdGFzZXQiKSAlPiUKICBtdXRhdGUoc3ViPWdzdWIoJ3N1Yi0nLCcnLHN1YikpJT4lCiAgdHJhbnNmb3JtKHN1Yj1hcy5pbnRlZ2VyKHN1YikpICU+JQogIG11dGF0ZShzY2FsZSA9IGFzLmZhY3RvcihpZmVsc2Uoc2NhbGUgPT0gIklEQVEtTkEiLCAiSURBUU5BIiwgIklEQVEiKSkpCgpybShERi5kMSwgREYuZDIsIERGLmQzLCBERi5kNCkKYGBgCgojIyA1LjIgUmVsaWFiaWxpdHkgb2YgSURBUQpDaGVjayB0aGUgcmVsaWFiaWxpdHkgb2YgdGhlIElEQVEgc2NhbGU6CmBgYHtyfQpERi5pZGFxICU+JSAKICBmaWx0ZXIoc2NhbGUgPT0gIklEQVEiKSAlPiUKICAjZmlsdGVyKCFzdWIgJWluJSBzdWJfZXgpICU+JSAKICBzZWxlY3QoLXNjYWxlLCAtc3Vic2NhbGUpICAlPiUKICBzcHJlYWQoaXRlbW5yLCB2YWx1ZSkgJT4lCiAgc2VsZWN0KC1zdWIsIC1kYXRhc2V0KSAlPiUKICBwc3ljaDo6YWxwaGEobmEucm0gPSBUUlVFKQpgYGAKCiMjIDUuMyBSZWxpYWJpbGl0eSBvZiBJREFRLU5BCkNoZWNrIHRoZSByZWxpYWJpbGl0eSBvZiB0aGUgSURBUS1OQSBzY2FsZToKYGBge3J9CkRGLmlkYXEgJT4lIAogIGZpbHRlcihzY2FsZSA9PSAiSURBUU5BIikgJT4lCiAgZmlsdGVyKCFzdWIgJWluJSAgc3ViX2V4KSAlPiUgCiAgc2VsZWN0KC1zY2FsZSwgLXN1YnNjYWxlKSAgJT4lCiAgc3ByZWFkKGl0ZW1uciwgdmFsdWUpICU+JQogIHNlbGVjdCgtc3ViLCAtZGF0YXNldCkgJT4lCiAgcHN5Y2g6OmFscGhhKG5hLnJtID0gVFJVRSkKYGBgCgoKCiMjIDUuNCBJREFRIHBlciBzdWJqZWN0CkNhbGN1bGF0ZSB0aGUgSURBUSBwZXIgc3ViamVjdDoKYGBge3J9CkRGLmlkYXEgPC0gREYuaWRhcSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoc3ViLGRhdGFzZXQsIHNjYWxlKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKHNjb3JlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGVfYXQodmFycygtc2NvcmUpLGFzLmZhY3RvcikKYGBgCgojIyA1LjUgVmlzdWFsaXNlIHRoZSBzY29yZXMKVmlzdWFsaXNlIHRoZSBzY29yZXMgYWNyb3NzIHRoZSBkYXRhc2V0cyBhbmQgc2NhbGVzIChGaWd1cmUgUzEpOgpgYGB7cn0KaWRhcV9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKERGLmlkYXEsIG1lYXN1cmV2YXI9InNjb3JlIiwgYmV0d2VlbnZhcnM9ImRhdGFzZXQiLCB3aXRoaW52YXJzPSAic2NhbGUiLCBpZHZhcj0ic3ViIikKCkZTMSA8LSBERi5pZGFxICU+JQogIGdyb3VwX2J5KHN1YixkYXRhc2V0LCBzY2FsZSkgJT4lCiAgZ2dwbG90KC4sYWVzKHg9ZGF0YXNldCx5PXNjb3JlLGZpbGw9ZGF0YXNldCwgZ3JvdXAgPSBkYXRhc2V0KSkrCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAuNzUsIGNvbG91ciA9ICJCbGFjayIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkYXRhc2V0KSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoID0gLjA1KSwgc2l6ZSA9IC41LCBzaGFwZSA9IDIxLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PWRhdGFzZXQseT1zY29yZSkscG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4xLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGlkYXFfc3VtLCBhZXMoeCA9IGRhdGFzZXQsIHkgPSBzY29yZSksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBpZGFxX3N1bSwgYWVzKHg9ZGF0YXNldCx5PXNjb3JlLCB5bWluID0gc2NvcmUtY2ksIHltYXggPSBzY29yZStjaSksIHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMywgeSA9IDApLCB3aWR0aCA9IC4wNSkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJHcmV5cyIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiR3JleXMiKSArCiAgeWxhYihwYXN0ZSgic2NvcmUgKDAtMTUwKSIpKSArIAogIGdndGl0bGUocGFzdGUoIklEQVEgc2NvcmVzIGFjcm9zcyBkYXRhc2V0cyIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGZhY2V0X3dyYXAofnNjYWxlKQpGUzEKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL1MxLlRJRkYiLCBwbG90ID0gRlMxLCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKCmBgYAoKVmlzdWFsaXNlIHRoZSBzY29yZXMgZm9yIElEQVEgc2NhbGUgb25seSAoRmlndXJlIDFBKToKYGBge3J9CmlkYXFfc3VtIDwtIHN1bW1hcnlTRXdpdGhpbihERi5pZGFxLCBtZWFzdXJldmFyPSJzY29yZSIsIHdpdGhpbnZhcnM9ICJzY2FsZSIsIGlkdmFyPSJzdWIiKQogCkYxQSA8LSBERi5pZGFxICU+JQogIGZpbHRlcihzY2FsZSA9PSAiSURBUSIpICU+JQogIGdyb3VwX2J5KHN1YikgJT4lCiAgZ2dwbG90KC4sYWVzKHggPSAxLCB5PXNjb3JlLCBmaWxsID0gIkJsYWNrIikpKwogIGdlb21fZmxhdF92aW9saW4ocG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4yLCB5ID0gMCksYWRqdXN0ID0yLCB0cmltID0gRkFMU0UsIGFscGhhID0gLjc1LCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gZGF0YXNldCksIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4wNSksIHNpemUgPSAuNSwgc2hhcGUgPSAyMSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fYm94cGxvdChhZXMoeD0xLHk9c2NvcmUpLHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMTIsIHkgPSAwKSxvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gLjUsIHdpZHRoID0gLjEsIGNvbG91ciA9ICJibGFjayIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gaWRhcV9zdW0gJT4lIGZpbHRlcihzY2FsZSA9PSAiSURBUSIpLCBhZXMoeCA9IDAuOTUsIHkgPSBzY29yZSksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBpZGFxX3N1bSAlPiUgZmlsdGVyKHNjYWxlID09ICJJREFRIiksIGFlcyh4PTAuOTUseT1zY29yZSwgeW1pbiA9IHNjb3JlLWNpLCB5bWF4ID0gc2NvcmUrY2kpLCBwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjMsIHkgPSAwKSwgd2lkdGggPSAuMDUpKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiR3JleXMiKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIkdyZXlzIikgKwogICN0aGVtZV9jbGFzc2ljKCkgKyAKICBjb29yZF9maXhlZChyYXRpbyA9IDEvOTApICsgCiAgeWxhYihwYXN0ZSgiRGlzcG9zaXRpb25hbCBhbnRocm9wb21vcnBoaXNtICgwLTE1MCkiKSkgKyAKICAjZ2d0aXRsZShwYXN0ZSgiRGlzcG9zaXRpb25hbCBhbnRocm9wb21vcnBoaXNtIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAKICApCkYxQQpnZ3NhdmUoImV4cGVyaW1lbnQxL2ZpZ3VyZXMvRjFBLlRJRkYiLCBwbG90ID0gRjFBLCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgojIyA1LjYgTWVkaWFuIGFuZCBpbnRlcnF1YXJ0aWxlIHJhbmdlIHBlciBkYXRhc2V0CkNhbGN1bGF0ZSB0aGUgbWVkaWFuIElRUiBwZXIgZGF0YXNldCAodGFibGUgUzIpOgpgYGB7cn0KREYuaWRhcSAlPiUKICAjZmlsdGVyKCFzdWIgJWluJSAgc3ViX2V4KSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KHNjYWxlLGRhdGFzZXQpICU+JQogIGRwbHlyOjpzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKHNjb3JlKSwKICAgICAgICAgICAgaXFyID0gSVFSKHNjb3JlKSkKYGBgCgojIDYuIFJPSSByZXN1bHRzIHsudGFic2V0fQoKIyMgNi4xIERhdGEgd3JhbmdsaW5nCkNyZWF0ZSBmdW5jdGlvbiB0byBsb2FkIHRoZSBkYXRhIGZvciB0aGUgZGlmZmVyZW50IG5ldHdvcmtzOgpgYGB7cn0Kcm9pX2V4dHJhY3QgPC0gZnVuY3Rpb24oZGF0YXNldG5vLCBzdWJzdGFydCwgc3ViZW5kLCBuZXR3b3JrLCBucm9pKSB7CiAgCiAgZGlyX2xzKHBhc3RlKCJleHBlcmltZW50MS9kYXRhc2V0XyIsIGRhdGFzZXRubywgIi9kZXJpdmF0aXZlcy9yb2kvIiwgbmV0d29yaywgc2VwID0gIiIpLCByZWdleHAgPSAiXFwudHN2JCIpICU+JSAKICAgIG1hcF9kZnIocmVhZC5kZWxpbSwgc2VwID0gIlx0IiwgLmlkID0gImlkIiwgaGVhZGVyID0gRkFMU0UpICAlPiUKICAgIG11dGF0ZShkYXRhc2V0ID0gZGF0YXNldG5vKSAlPiUKICAgIG11dGF0ZShuZXR3b3JrID0gbmV0d29yaykgJT4lCiAgICBtdXRhdGUobmV0d29yayA9IHN0cl9leHRyYWN0KG5ldHdvcmssICJ0b218cGFpbiIpKSAlPiUKICAgIG11dGF0ZShpZCA9IHN0cl9leHRyYWN0KGlkLCAiZG1wZmN8bW1wZmN8dm1wZmN8bHRwanxydHBqfHByZWN8YW1jY3xsbWZnfHJtZmd8bHMyfHJzMnxsaW5zdWxhfHJpbnN1bGEiKSkgJT4lCiAgICBkcGx5cjo6cmVuYW1lKHJvaSA9IGlkLCBjb250cmFzdCA9IFYxKSAlPiUKICAgIG11dGF0ZShzdWIgPSByZXAoc3Vic3RhcnQ6c3ViZW5kLCB0aW1lcz1ucm9pLCBlYWNoPTEpKSAlPiUKICAgIHNlbGVjdCg1LDMsNCwxOjIpCn0gCmBgYAoKTG9hZCB0aGUgZGF0YSBmb3IgdGhlIFRoZW9yeS1vZi1NaW5kIG5ldHdvcms6CmBgYHtyfQpERi5kMSA8LSByb2lfZXh0cmFjdCgxLCAxMDEsIDEyOSwgInRvbSIsIDYpCkRGLmQyLmEgPC0gcm9pX2V4dHJhY3QoMiwgMjAxLCAyMDIsICJ0b20vMjAxXzIwMiIsIDYpCkRGLmQyLmIgPC0gcm9pX2V4dHJhY3QoMiwgMjAzLCAyMzUsICJ0b20iLCA2KQpERi5kMyA8LSByb2lfZXh0cmFjdCgzLCAzMDEsIDMyMiwgInRvbSIsIDYpCkRGLmQ0IDwtIHJvaV9leHRyYWN0KDQsIDQwMSwgNDIyLCAidG9tIiwgNikKCkRGLnRlbXAgPC0gYmluZF9yb3dzKERGLmQxLCBERi5kMi5hLCBERi5kMi5iLCBERi5kMywgREYuZDQpIApgYGAKCkxvYWQgdGhlIGRhdGEgZm9yIHRoZSBQYWluIE1hdHJpeDoKYGBge3J9CkRGLmQxIDwtIHJvaV9leHRyYWN0KDEsIDEwMSwgMTI5LCAicGFpbiIsIDcpCkRGLmQyLmEgPC0gcm9pX2V4dHJhY3QoMiwgMjAxLCAyMDIsICJwYWluLzIwMV8yMDIvIiwgNykKREYuZDIuYiA8LSByb2lfZXh0cmFjdCgyLCAyMDMsIDIzNSwgInBhaW4iLCA3KQpERi5kMyA8LSByb2lfZXh0cmFjdCgzLCAzMDEsIDMyMiwgInBhaW4iLCA3KQpERi5kNCA8LSByb2lfZXh0cmFjdCg0LCA0MDEsIDQyMiwgInBhaW4iLCA3KQoKREYucm9pIDwtIGJpbmRfcm93cyhERi50ZW1wLCBERi5kMSwgREYuZDIuYSwgREYuZDIuYiwgREYuZDMsIERGLmQ0KQoKcm0oREYuZDEsIERGLmQyLmEsIERGLmQyLmIsIERGLmQzLCBERi5kNCwgREYudGVtcCkKYGBgCgpSZW9yZGVyIFJPSSBuYW1lcyBmb3IgcGxvdHM6CmBgYHtyfQpvcmRlciA8LSBjKCJydHBqIiwgImx0cGoiLCAicHJlYyIsICJ2bXBmYyIsIm1tcGZjIiwiZG1wZmMiLCAicnMyIiwgImxzMiIsICJyaW5zdWxhIiwgImxpbnN1bGEiLCAicm1mZyIsICJsbWZnIiwgImFtY2MiKSAgCgpERi5yb2kgPC0gREYucm9pICU+JQogIG11dGF0ZV9hdCh2YXJzKC1jb250cmFzdCksYXMuZmFjdG9yKSAlPiUKICBncm91cF9ieShzdWIsIGRhdGFzZXQpICU+JQogIG11dGF0ZShyb2kgPSBmY3RfcmVsZXZlbChyb2ksIG9yZGVyKSkKYGBgCgojIyA2LjIgVGhlb3J5LW9mLU1pbmQgbmV0d29yayBhY3RpdmF0aW9uIGFjcm9zcyBkYXRhc2V0czoKUGxvdCB0aGUgVG9NIGFjdGl2aXR5IGFjcm9zcyByZWdpb25zIGFuZCBkYXRhc2V0cyAoRmlndXJlIFMyKToKYGBge3J9CnJvaV9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKERGLnJvaSwgbWVhc3VyZXZhcj0iY29udHJhc3QiLCBiZXR3ZWVudmFycz0iZGF0YXNldCIsIHdpdGhpbnZhcnM9IGMoInJvaSIsIm5ldHdvcmsiKSwgaWR2YXI9InN1YiIpCgpGUzIgPC0gREYucm9pICU+JQogIGZpbHRlcihuZXR3b3JrID09ICJ0b20iKSAlPiUKICBnZ3Bsb3QoLixhZXMoeD1yb2kseT1jb250cmFzdCxmaWxsPXJvaSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX2ZsYXRfdmlvbGluKHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMiwgeSA9IDApLGFkanVzdCA9MiwgdHJpbSA9IEZBTFNFLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gcm9pLCBmaWxsID0gcm9pKSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoID0gLjA1KSwgc2l6ZSA9IC41LCBzaGFwZSA9IDIxLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PXJvaSx5PWNvbnRyYXN0KSxwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjEsIHkgPSAwKSxvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gLjUsIHdpZHRoID0gLjEsIGNvbG91ciA9ICJibGFjayIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gcm9pX3N1bSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpLCBhZXMoeCA9IHJvaSwgeSA9IGNvbnRyYXN0KSwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSguMyksIGNvbG91ciA9ICJCTEFDSyIpKwogIGdlb21fZXJyb3JiYXIoZGF0YSA9IHJvaV9zdW0gJT4lIGZpbHRlcihuZXR3b3JrID09ICJ0b20iKSwgYWVzKHg9cm9pLHk9Y29udHJhc3QsIHltaW4gPSBjb250cmFzdC1jaSwgeW1heCA9IGNvbnRyYXN0K2NpKSwgcG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4zLCB5ID0gMCksIHdpZHRoID0gLjA1KSsKICAjdGhlbWVfY2xhc3NpYygpICsgCiAgeWxhYigiQ29udHJhc3QgZXN0aW1hdGVzIChtZW50YWwgPiBwYWluKSIpICsgCiAgeGxhYigiUmVnaW9uLW9mLWludGVyZXN0IikgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsgCiAgZ2d0aXRsZShwYXN0ZSgiVGhlb3J5LW9mLU1pbmQgbmV0d29yayBjb250cmFzdHMgZXN0aW1hdGVzIGFjcm9zcyBkYXRhc2V0cyBhbmQgcmVnaW9ucyIpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0KSAKRlMyCgpnZ3NhdmUoImV4cGVyaW1lbnQxL2ZpZ3VyZXMvUzIuVElGRiIsIHBsb3QgPSBGUzIsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKClBsb3QgdGhlIFRvTSBhY3Rpdml0eSBhY3Jvc3MgcmVnaW9ucyAoRmlndXJlIDFDKToKYGBge3J9CnJvaV9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKERGLnJvaSwgbWVhc3VyZXZhcj0iY29udHJhc3QiLCB3aXRoaW52YXJzPSBjKCJyb2kiLCJuZXR3b3JrIiksIGlkdmFyPSJzdWIiKQoKRjFDIDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAidG9tIikgJT4lCiAgZ2dwbG90KC4sYWVzKHg9cm9pLHk9Y29udHJhc3QsZmlsbD1yb2kpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHJvaSwgZmlsbCA9IHJvaSksIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4wNSksIHNpemUgPSAuNSwgc2hhcGUgPSAyMSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fYm94cGxvdChhZXMoeD1yb2kseT1jb250cmFzdCkscG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4xLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHJvaV9zdW0gJT4lIGZpbHRlcihuZXR3b3JrID09ICJ0b20iKSwgYWVzKHggPSByb2ksIHkgPSBjb250cmFzdCksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSByb2lfc3VtICU+JSBmaWx0ZXIobmV0d29yayA9PSAidG9tIiksIGFlcyh4PXJvaSx5PWNvbnRyYXN0LCB5bWluID0gY29udHJhc3QtY2ksIHltYXggPSBjb250cmFzdCtjaSksIHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMywgeSA9IDApLCB3aWR0aCA9IC4wNSkrCiAgI3RoZW1lX2NsYXNzaWMoKSArIAogIHlsYWIoIlRoZW9yeS1vZi1NaW5kIG5ldHdvcmsgYWN0aXZhdGlvbiIpICsgCiAgeGxhYigiUmVnaW9uLW9mLWludGVyZXN0IikgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsgCiAgI2dndGl0bGUocGFzdGUoIlRoZW9yeS1vZi1NaW5kIG5ldHdvcmsgY29udHJhc3RzIGVzdGltYXRlcyBhY3Jvc3MgZGF0YXNldHMgYW5kIHJlZ2lvbnMiKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSAKCkYxQwoKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL0YxQy5USUZGIiwgcGxvdCA9IEYxQywgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKIyMgNi4zIFBhaW4gTWF0cml4IGFjdGl2YXRpb24gYWNyb3NzIGRhdGFzZXRzClBsb3QgdGhlIFBhaW4gTWF0cml4IGFjdGl2aXR5IGFjcm9zcyByZWdpb25zIGFuZCBkYXRhc2V0cyAoRmlndXJlIFMzKToKYGBge3J9CkZTMyA8LSBERi5yb2kgJT4lCiAgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSAlPiUKICBnZ3Bsb3QoLixhZXMoeD1yb2kseT1jb250cmFzdCxmaWxsPXJvaSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX2ZsYXRfdmlvbGluKHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMiwgeSA9IDApLGFkanVzdCA9MiwgdHJpbSA9IEZBTFNFLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gcm9pLCBmaWxsID0gcm9pKSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoID0gLjA1KSwgc2l6ZSA9IC41LCBzaGFwZSA9IDIxLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PXJvaSx5PWNvbnRyYXN0KSxwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjEsIHkgPSAwKSxvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gLjUsIHdpZHRoID0gLjEsIGNvbG91ciA9ICJibGFjayIpICsKICBnZW9tX3BvaW50KGRhdGEgPSByb2lfc3VtICU+JSBmaWx0ZXIobmV0d29yayA9PSAicGFpbiIpLCBhZXMoeCA9IHJvaSwgeSA9IGNvbnRyYXN0KSwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSguMyksIGNvbG91ciA9ICJCTEFDSyIpKwogIGdlb21fZXJyb3JiYXIoZGF0YSA9IHJvaV9zdW0gJT4lIGZpbHRlcihuZXR3b3JrID09ICJwYWluIiksIGFlcyh4PXJvaSx5PWNvbnRyYXN0LCB5bWluID0gY29udHJhc3QtY2ksIHltYXggPSBjb250cmFzdCtjaSksIHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMywgeSA9IDApLCB3aWR0aCA9IC4wNSkrCiAgI3RoZW1lX2NsYXNzaWMoKSArIAogIHlsYWIoIkNvbnRyYXN0IGVzdGltYXRlcyAocGFpbiA+IG1lbnRhbCkiKSArIAogIHhsYWIoIlJlZ2lvbi1vZi1pbnRlcmVzdCIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKyAKICBnZ3RpdGxlKHBhc3RlKCJQYWluIE1hdHJpeCBjb250cmFzdHMgZXN0aW1hdGVzIGFjcm9zcyBkYXRhc2V0cyBhbmQgcmVnaW9ucyIpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0KQpGUzMKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL1MzLlRJRkYiLCBwbG90ID0gRlMzLCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgojIyA2LjUgQ29tYmluZSBJREFRIHNjb3JlcyBhbmQgUk9JIGRhdGE6CkNyZWF0ZSBvbmUgREY6CmBgYHtyfQpERi5yb2kgPC0gREYuaWRhcSAlPiUgCiAgZ3JvdXBfYnkoc3ViLGRhdGFzZXQsIHNjYWxlKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGxlZnRfam9pbihERi5yb2ksIERGLmlkYXEsIGJ5ID0gYygic3ViIiwiZGF0YXNldCIpLCBrZWVwID0gRkFMU0UpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209c2NhbGUsIHZhbHVlc19mcm9tID0gc2NvcmUpICMKYGBgCgpDZW50ZXIgdGhlIHZhcmlhYmxlcyBmb3IgdGhlIGZvcm1hbCBhbmFseXNpczoKYGBge3J9CkRGLnJvaSRjZW50X0lEQVFOQSA8LSBzY2FsZShERi5yb2kkSURBUU5BLCBzY2FsZSA9IFRSVUUpCkRGLnJvaSRjZW50X0lEQVEgPC0gc2NhbGUoREYucm9pJElEQVEsIHNjYWxlID0gVFJVRSkKREYucm9pIDwtIERGLnJvaSAlPiUgZ3JvdXBfYnkocm9pKSAlPiUgbXV0YXRlKGNlbnRfY29udHJhc3QgPSBzY2FsZShjb250cmFzdCwgc2NhbGUgPVRSVUUpKSAjc2NhbGUgcGVyIHJvaSAoYW5hbHlzZXMgYXJlIGRvbmUgcGVyIHJvaSkKYGBgCgojIDcuIElEQVEgc2NvcmVzIGFuZCBUb00gYWN0aXZpdHkgey50YWJzZXR9CgojIyA3LjEgUGxvdCBUb00gYW5kIElEQVEKQ3JlYXRlIHNjYXR0ZXJwbG90cyB3aXRoIGxpbmVhciBhbmQgbm9uLWxpbmVhciBsaW5lcyBmb3IgVG9NIG5ldHdvcms6IApgYGB7cn0KRjFEIDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAidG9tIikgJT4lCiAgZ2dwbG90KGFlcyh4PWNlbnRfSURBUSwgeT1jZW50X2NvbnRyYXN0KSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41LHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCwgc2U9VFJVRSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyPSIjMDA3MkIyIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4KyBJKHheMiksIHNlPVRSVUUsIHNob3cubGVnZW5kPUZBTFNFLCBjb2xvdXIgPSAiI0Q1NUUwMCIpICsKICBjb29yZF9maXhlZChyYXRpbyA9IDEvMSkgKwogIGxhYnMoCiAgICB4PSJEaXNwb3NpdGlvbmFsIGFudGhyb3BvbW9ycGhpc20iLAogICAgeT0iVGhlb3J5LW9mLU1pbmQgbmV0d29yayBhY3RpdmF0aW9uIgogICkgIysgdGhlbWVfY2xhc3NpYygpCgpGMUQgCgpnZ3NhdmUoImV4cGVyaW1lbnQxL2ZpZ3VyZXMvRjFELlRJRkYiLCBwbG90ID0gRjFELCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgpDcmVhdGUgc2NhdHRlcnBsb3RzIHdpdGggbGluZWFyIGFuZCBub24tbGluZWFyIGxpbmVzIGZvciBpbmRpdmlkdWFsIHJlZ2lvbnMgb2YgVG9NIG5ldHdvcms6IApgYGB7cn0KdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gNykpIAoKRjFFIDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAidG9tIikgJT4lCiAgZ2dwbG90KGFlcyh4PWNlbnRfSURBUSwgeT1jZW50X2NvbnRyYXN0KSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41LHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCwgc2U9VFJVRSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyPSIjMDA3MkIyIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4KyBJKHheMiksIHNlPVRSVUUsIHNob3cubGVnZW5kPUZBTFNFLCBjb2xvdXIgPSAiI0Q1NUUwMCIpICsKICBjb29yZF9maXhlZChyYXRpbyA9IDEvMSkgKwogIGZhY2V0X3dyYXAofnJvaSwgbmNvbCA9IDYpICsKICBsYWJzKAogICAgeD0iRGlzcG9zaXRpb25hbCBhbnRocm9wb21vcnBoaXNtIiwKICAgIHk9IkNvbnRyYXN0IGVzdGltYXRlcyIKICApICMrIHRoZW1lX2NsYXNzaWMoKSAKCkYxRQoKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL0YxRS5USUZGIiwgcGxvdCA9IEYxRSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCgpgYGAKCgojIyA3LjIgQ3JlYXRlIGEgZnVuY3Rpb24gZm9yIHRoZSBCYXllc2lhbiByZWdyZXNzaW9uIG1vZGVsczoKCkZvciB0aGUgZm9ybWFsIGFuYWx5c2lzIHdlIHdpbGwgdGVzdCBhIGxpbmVhciBhbmQgcXVhZHJhdGljIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIElEQVEgYW5kIFRvTSBuZXR3b3JrIGFjdGl2aXR5OgpgYGB7cn0KREYucm9pJGNlbnRfSURBUTIgPC0gREYucm9pJGNlbnRfSURBUV4yCmBgYAoKV2UgcnVuIHRoZSBtb2RlbHMgd2l0aCB1bmluZm9ybWF0aXZlIChkZWZhdWx0KSBwcmlvcnMgYW5kIGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIHJ1biBpdCBmb3IgZWFjaCByZWdpb24gc2VwYXJhdGVseToKYGBge3J9CnJlZ19tb2RlbCA8LSBmdW5jdGlvbihyZWdpb24pewogIGJybShmb3JtdWxhID0gY2VudF9jb250cmFzdCB+IGNlbnRfSURBUSArIGNlbnRfSURBUTIsCiAgICAgIGRhdGEgPSBERi5yb2kgJT4lIGZpbHRlcihyb2kgPT0gcmVnaW9uKSwKICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sCiAgICAgIGNoYWlucyA9IDQsCiAgICAgIGl0ZXIgPSA0MDAwLAogICAgICBzZWVkID0gNDIsICNzbyB0aGUgbW9kZWwgaXMgcmVwcm9kdWNpYmxlCiAgICAgIGZpbGUgPSBwYXN0ZTAoImV4cGVyaW1lbnQxL21vZGVscy9yZWdpb25zLyIsIHJlZ2lvbiwgIi5SRFMiLCBzZXAgPSAiIikpCn0KYGBgCgojIyA3LjMgUnVuIHRoZSBUb00gcmVncmVzc2lvbiBtb2RlbHM6ClJ1biB0aGUgbW9kZWxzIGZvciB0aGUgVG9NIG5ldHdvcmsgZmlyc3QuIEl0IHdpbGwgbG9hZCB0aGUgbW9kZWwgaWYgaXQgaXMgYWxyZWFkeSBjYWxjdWxhdGVkOgpgYGB7cn0KcnRwaiA8LSByZWdfbW9kZWwoInJ0cGoiKQpsdHBqIDwtIHJlZ19tb2RlbCgibHRwaiIpCnByZWMgPC0gcmVnX21vZGVsKCJwcmVjIikKdm1wZmMgPC0gcmVnX21vZGVsKCJ2bXBmYyIpCm1tcGZjIDwtIHJlZ19tb2RlbCgibW1wZmMiKQpkbXBmYyA8LSByZWdfbW9kZWwoImRtcGZjIikKYGBgCgpHZXQgdGhlIHN1bW1hcmllcyAodmVyYmF0aW0sIHJ1biBpbmRpdmlkdWFsbHkpOgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzdW1tYXJ5KHJ0cGopCnN1bW1hcnkobHRwaikKc3VtbWFyeShwcmVjKQpzdW1tYXJ5KHZtcGZjKQpzdW1tYXJ5KG1tcGZjKQpzdW1tYXJ5KGRtcGZjKQpgYGAKCiMjIDcuNCBUb00gbW9kZWwgb3V0cHV0OgpVc2Ugc2pQbG90IHRvIGNyZWF0ZSBodG1sIHRhYmxlcyBmb2xsb3dpbmcgW3Byb2NlZHVyZSBvdXRsaW5lZCBoZXJlXShodHRwczovL3N0cmVuZ2VqYWNrZS5naXRodWIuaW8vc2pQbG90L2FydGljbGVzL3RhYl9iYXllcy5odG1sKToKYGBge3J9CnRhYl9tb2RlbCgKICBydHBqLGx0cGoscHJlYyx2bXBmYyxtbXBmYyxkbXBmYywKICBzaG93LnNlID0gVFJVRSwKICAjY29sbGFwc2Uuc2UgPSBUUlVFLAogIHByZWQubGFiZWxzID0gYygiSW50ZXJjZXB0IiwgImxpbmVhciBwcmVkaWN0b3IiLCAicXVhZHJhdGljIHByZWRpY3RvciIpLAogIGR2LmxhYmVscyA9IGMoInJ0cGoiLCAibHRwaiIsInByZWMiLCJ2bXBmYyIsIm1tcGZjIiwiZG1wZmMiKSwKICBzaG93Lm9icz1GQUxTRQopCmBgYAoKIyMgNy41IFBvc3RlcmlvciBwbG90czoKQ3JlYXRlIHBsb3RzIGJhc2VkIG9uIFt0aGlzIHR1dG9yaWFsXShodHRwczovL3d3dy5yZW5zdmFuZGVzY2hvb3QuY29tL3R1dG9yaWFscy9yLWxpbmVhci1yZWdyZXNzaW9uLWJheWVzaWFuLXVzaW5nLWJybXMvKToKYGBge3J9CnRvbV9jb21iaW5lZCA8LSBiaW5kX3Jvd3MoInJ0cGoiID0gYXNfdGliYmxlKGFzLm1jbWMocnRwaiwgIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSwgY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImx0cGoiID0gYXNfdGliYmxlKGFzLm1jbWMobHRwaiwgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVjIiA9IGFzX3RpYmJsZShhcy5tY21jKHByZWMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAidm1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWModm1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAibW1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWMobW1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiZG1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWMoZG1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAuaWQgPSAicm9pIikKCm9yZGVyIDwtIGMoInJ0cGoiLCAibHRwaiIsICJwcmVjIiwgInZtcGZjIiwibW1wZmMiLCJkbXBmYyIsICJyczIiLCAibHMyIiwgInJpbnN1bGEiLCAibGluc3VsYSIsICJybWZnIiwgImxtZmciLCAiYW1jYyIpICAKCnRvbV9jb21iaW5lZCA8LSB0b21fY29tYmluZWQgJT4lCiAgZHBseXI6OnJlbmFtZShsaW5lYXIgPSBiX2NlbnRfSURBUSwgcXVhZHJhdGljID0gYl9jZW50X0lEQVEyKSAlPiUKICBwaXZvdF9sb25nZXIoYygibGluZWFyIiwgInF1YWRyYXRpYyIpLG5hbWVzX3RvID0gInZhcklEQVEiKSAlPiUKICBtdXRhdGUocm9pID0gZmN0X3JlbGV2ZWwocm9pLCBvcmRlclsxOjZdKSkKYGBgCgpQbG90IHRoZSBkaXN0cmlidXRpb25zOgpgYGB7cn0KRjIgPC0gdG9tX2NvbWJpbmVkICU+JQogIG11dGF0ZV9hdCh2YXJzKC12YWx1ZSksYXMuZmFjdG9yKSAlPiUKICBkcGx5cjo6cmVuYW1lKHByZWRpY3RvciA9IHZhcklEQVEpICU+JQogIGdncGxvdCguLCBhZXModmFsdWUsIGZpbGwgPSBwcmVkaWN0b3IpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjUpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIiwgbGluZXR5cGUgPSAyKSArCiAgZ2d0aXRsZShwYXN0ZSgiUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZm9yIHRoZSBUaGVvcnktb2YtTWluZCBuZXR3b3JrIikpICsgCiAgZmFjZXRfd3JhcCh+cm9pLCBuY29sID0xKSArCiAgY29vcmRfZml4ZWQocmF0aW8gPSAxLzQwKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSA4KSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkrIAogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpGMgoKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL0YyLlRJRkYiLCBwbG90ID0gRjIsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKCiMgOC4gSURBUSBzY29yZXMgYW5kIFBhaW4gTWF0cml4IGFjdGl2aXR5IHsudGFic2V0fQoKIyMgOC4xIFBsb3QgUGFpbiBNYXRyaXggYW5kIElEQVEKQ3JlYXRlIHNjYXR0ZXJwbG90cyB3aXRoIGxpbmVhciBhbmQgbm9uLWxpbmVhciBsaW5lcyBmb3IgdGhlIFBhaW4gTWF0cml4OiAKYGBge3J9ClM0IDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAicGFpbiIpICU+JQogIGdncGxvdChhZXMoeD1jZW50X0lEQVEsIHk9Y2VudF9jb250cmFzdCkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSxzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eSB+IHgsIHNlPVRSVUUsIHNob3cubGVnZW5kID0gRkFMU0UsIGNvbG91cj0iIzAwNzJCMiIpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCsgSSh4XjIpLCBzZT1UUlVFLCBzaG93LmxlZ2VuZD1GQUxTRSwgY29sb3VyID0gIiNENTVFMDAiKSArCiAgI2Nvb3JkX2ZpeGVkKHJhdGlvID0gMjUvMSkgKwogIGxhYnMoCiAgICB4PSJJREFRIHNjb3JlIiwKICAgIHk9ImNvbnRyYXN0IChwYWluIHZzIG1lbnRhbCkiCiAgKSArIHRoZW1lX2NsYXNzaWMoKQoKUzQgCgpnZ3NhdmUoImV4cGVyaW1lbnQxL2ZpZ3VyZXMvUzQuVElGRiIsIHBsb3QgPSBTNCwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKQ3JlYXRlIHNjYXR0ZXJwbG90cyB3aXRoIGxpbmVhciBhbmQgbm9uLWxpbmVhciBsaW5lcyBmb3IgaW5kaXZpZHVhbCByZWdpb25zIG9mIHRoZSBQYWluIE1hdHJpeDogCmBgYHtyfQpTNSA8LSBERi5yb2kgJT4lCiAgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y2VudF9JREFRLCB5PWNlbnRfY29udHJhc3QpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4LCBzZT1UUlVFLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXI9IiMwMDcyQjIiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eSB+IHgrIEkoeF4yKSwgc2U9VFJVRSwgc2hvdy5sZWdlbmQ9RkFMU0UsIGNvbG91ciA9ICIjRDU1RTAwIikgKwogICNjb29yZF9maXhlZChyYXRpbyA9IDI1LzEpICsKICBsYWJzKAogICAgeD0iSURBUSBzY29yZSIsCiAgICB5PSJjb250cmFzdCAocGFpbiB2cyBtZW50YWwpIgogICkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGZhY2V0X3dyYXAofnJvaSwgbnJvdyA9IDIpCgpTNSAKCmdnc2F2ZSgiZXhwZXJpbWVudDEvZmlndXJlcy9TNS5USUZGIiwgcGxvdCA9IFM1LCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgoKIyMgOC4yIFJlZ3Jlc3Npb24gbW9kZWxzIGZvciB0aGUgUGFpbiBNYXRyaXg6ClJ1biB0aGUgbW9kZWxzIGZvciB0aGUgUGFpbiBNYXRyaXggKGNvbnRyb2wgbmV0d29yaykuIEl0IHdpbGwgbG9hZCB0aGUgbW9kZWwgaWYgaXQgaXMgYWxyZWFkeSBjYWxjdWxhdGVkOgpgYGB7cn0KcnMyIDwtIHJlZ19tb2RlbCgicnMyIikKbHMyIDwtIHJlZ19tb2RlbCgibHMyIikKcmluc3VsYSA8LSByZWdfbW9kZWwoInJpbnN1bGEiKQpsaW5zdWxhIDwtIHJlZ19tb2RlbCgibGluc3VsYSIpCnJtZmcgPC0gcmVnX21vZGVsKCJybWZnIikKbG1mZyA8LSByZWdfbW9kZWwoImxtZmciKQphbWNjIDwtIHJlZ19tb2RlbCgiYW1jYyIpCmBgYAoKR2V0IHRoZSBzdW1tYXJpZXMgKHZlcmJhdGltLCBydW4gaW5kaXZpZHVhbGx5KToKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc3VtbWFyeShyczIpCnN1bW1hcnkobHMyKQpzdW1tYXJ5KHJpbnN1bGEpCnN1bW1hcnkobGluc3VsYSkKc3VtbWFyeShybWZnKQpzdW1tYXJ5KGxtZmcpCnN1bW1hcnkoYW1jYykKYGBgCgojIyA4LjMgUGFpbiBNYXRyaXggbW9kZWwgb3V0cHV0OgpVc2Ugc2pQbG90IHRvIGNyZWF0ZSBodG1sIHRhYmxlcyBmb2xsb3dpbmcgW3Byb2NlZHVyZSBvdXRsaW5lZCBoZXJlXShodHRwczovL3N0cmVuZ2VqYWNrZS5naXRodWIuaW8vc2pQbG90L2FydGljbGVzL3RhYl9iYXllcy5odG1sKToKYGBge3J9CnRhYl9tb2RlbCgKICByczIsbHMyLHJpbnN1bGEsbGluc3VsYSxybWZnLGxtZmcsYW1jYywKICBzaG93LnNlID0gVFJVRSwKICAjY29sbGFwc2Uuc2UgPSBUUlVFLAogIHByZWQubGFiZWxzID0gYygiSW50ZXJjZXB0IiwgImxpbmVhciBwcmVkaWN0b3IiLCAicXVhZHJhdGljIHByZWRpY3RvciIpLAogIGR2LmxhYmVscyA9IGMoInJzMiIsImxzMiIsInJpbnN1bGEiLCJsaW5zdWxhIiwicm1mZyIsImxtZmciLCJhbWNjIiksCiAgc2hvdy5vYnM9RkFMU0UKKQpgYGAKCiMjIDguNCBQb3N0ZXJpb3IgcGxvdHM6CkNyZWF0ZSBwbG90cyBiYXNlZCBvbiBbdGhpcyB0dXRvcmlhbF0oaHR0cHM6Ly93d3cucmVuc3ZhbmRlc2Nob290LmNvbS90dXRvcmlhbHMvci1saW5lYXItcmVncmVzc2lvbi1iYXllc2lhbi11c2luZy1icm1zLyk6CmBgYHtyfQpwYWluX2NvbWJpbmVkIDwtIGJpbmRfcm93cygicnMyIiA9IGFzX3RpYmJsZShhcy5tY21jKHJzMiwgIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSwgY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImxzMiIgPSBhc190aWJibGUoYXMubWNtYyhsczIsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAicmluc3VsYSIgPSBhc190aWJibGUoYXMubWNtYyhyaW5zdWxhLCBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImxpbnN1bGEiID0gYXNfdGliYmxlKGFzLm1jbWMobGluc3VsYSwgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJybWZnIiA9IGFzX3RpYmJsZShhcy5tY21jKHJtZmcsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAibG1mZyIgPSBhc190aWJibGUoYXMubWNtYyhsbWZnLCBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImFtY2MiID0gYXNfdGliYmxlKGFzLm1jbWMoYW1jYywgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIC5pZCA9ICJyb2kiKQoKcGFpbl9jb21iaW5lZCA8LSBwYWluX2NvbWJpbmVkICU+JQogIGRwbHlyOjpyZW5hbWUobGluZWFyID0gYl9jZW50X0lEQVEsIHF1YWRyYXRpYyA9IGJfY2VudF9JREFRMikgJT4lCiAgcGl2b3RfbG9uZ2VyKGMoImxpbmVhciIsICJxdWFkcmF0aWMiKSxuYW1lc190byA9ICJ2YXJJREFRIikgJT4lCiAgbXV0YXRlKHJvaSA9IGZjdF9yZWxldmVsKHJvaSwgb3JkZXJbNzoxM10pKQpgYGAKClBsb3QgdGhlIGRpc3RyaWJ1dGlvbnM6CmBgYHtyfQpTNiA8LSBwYWluX2NvbWJpbmVkICU+JQogIG11dGF0ZV9hdCh2YXJzKC12YWx1ZSksYXMuZmFjdG9yKSAlPiUKICBkcGx5cjo6cmVuYW1lKHByZWRpY3RvciA9IHZhcklEQVEpICU+JQogIGdncGxvdCguLCBhZXModmFsdWUsIGZpbGwgPSBwcmVkaWN0b3IpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjUpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIiwgbGluZXR5cGUgPSAyKSArCiAgZ2d0aXRsZShwYXN0ZSgiUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZm9yIHRoZSBQYWluIE1hdHJpeCIpKSArIAogIGZhY2V0X3dyYXAofnJvaSwgbmNvbCA9MSkgKwogIGNvb3JkX2ZpeGVkKHJhdGlvID0gMS80MCkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gOCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwNzJCMiIsICIjRDU1RTAwIikpCiN0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKClM2IAoKZ2dzYXZlKCJleHBlcmltZW50MS9maWd1cmVzL1M2LlRJRkYiLCBwbG90ID0gUzYsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKCgojIyA5IE9uZSBtb2RlbCBhY3Jvc3MgdGhlIG5ldHdvcmtzIAoKIyMgOS4xIFRoZW9yeS1vZi1NaW5kOgpBbGwgVG9NIHJlZ2lvbnMgY29tYmluZWQ6CmBgYHtyfQp0b20gPC0gYnJtKGZvcm11bGEgPSBjZW50X2NvbnRyYXN0IH4gY2VudF9JREFRICsgY2VudF9JREFRMiwKICAgICAgZGF0YSA9IERGLnJvaSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpLAogICAgICBmYW1pbHkgPSBnYXVzc2lhbiwKICAgICAgY2hhaW5zID0gNCwKICAgICAgaXRlciA9IDQwMDAsCiAgICAgIHNlZWQgPSA0MiwgI3NvIHRoZSBtb2RlbCBpcyByZXByb2R1Y2libGUKICAgICAgZmlsZSA9ICJleHBlcmltZW50MS9tb2RlbHMvcmVnaW9ucy90b20uUkRTIikKYGBgCgpTdW1tYXJ5OgpgYGB7cn0Kc3VtbWFyeSh0b20pCmBgYAoKIyMgOS4yIFBhaW4gTWF0cml4OgpBbGwgcGFpbiBtYXRyaXggcmVnaW9ucyBjb21iaW5lZDoKYGBge3J9CnBhaW4gPC0gYnJtKGZvcm11bGEgPSBjZW50X2NvbnRyYXN0IH4gY2VudF9JREFRICsgY2VudF9JREFRMiwKICAgICAgZGF0YSA9IERGLnJvaSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSwKICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sCiAgICAgIGNoYWlucyA9IDQsCiAgICAgIGl0ZXIgPSA0MDAwLAogICAgICBzZWVkID0gNDIsICNzbyB0aGUgbW9kZWwgaXMgcmVwcm9kdWNpYmxlCiAgICAgIGZpbGUgPSAiZXhwZXJpbWVudDEvbW9kZWxzL3JlZ2lvbnMvcGFpbi5SRFMiKQpgYGAKClN1bW1hcnk6CmBgYHtyfQpzdW1tYXJ5KHBhaW4pCmBgYAoKIyMgOS4zIFBvc3RlcmlvciBwbG90cyBmb3IgdGhlIHR3byBuZXR3b3JrczoKCmBgYHtyfQp0YWJfbW9kZWwoCiAgdG9tLCBwYWluLAogIHNob3cuc2UgPSBUUlVFLAogICNjb2xsYXBzZS5zZSA9IFRSVUUsCiAgcHJlZC5sYWJlbHMgPSBjKCJJbnRlcmNlcHQiLCAibGluZWFyIHByZWRpY3RvciIsICJxdWFkcmF0aWMgcHJlZGljdG9yIiksCiAgZHYubGFiZWxzID0gYygidG9tIiwicGFpbiIpLAogIHNob3cub2JzPUZBTFNFCikKYGBgCgojIyA5LjQgUG9zdGVyaW9yIHBsb3RzIGZvciB0aGUgdHdvIG5ldHdvcmtzOgoKYGBge3J9CnRvbV9hbGwgPC0gYmluZF9yb3dzKCJhbGwiID0gYXNfdGliYmxlKGFzLm1jbWModG9tLCAgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLCBjb21iaW5lX2NoYWlucyA9IFRSVUUpLCAuaWQgPSAibmV0d29yayIpICAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnJlbmFtZShsaW5lYXIgPSBiX2NlbnRfSURBUSwgcXVhZHJhdGljID0gYl9jZW50X0lEQVEyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKGMoImxpbmVhciIsICJxdWFkcmF0aWMiKSxuYW1lc190byA9ICJ2YXJJREFRIikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShuZXR3b3JrID0gInRvbSIpKQoKcGFpbl9hbGwgPC0gYmluZF9yb3dzKCJhbGwiID0gYXNfdGliYmxlKGFzLm1jbWMocGFpbiwgIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSwgY29tYmluZV9jaGFpbnMgPSBUUlVFKSwgLmlkID0gIm5ldHdvcmsiKSAgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUobGluZWFyID0gYl9jZW50X0lEQVEsIHF1YWRyYXRpYyA9IGJfY2VudF9JREFRMikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihjKCJsaW5lYXIiLCAicXVhZHJhdGljIiksbmFtZXNfdG8gPSAidmFySURBUSIpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobmV0d29yayA9ICJwYWluIikpCgp0b21fYWxsICU+JSBiaW5kX3Jvd3MoLiwgcGFpbl9hbGwpICU+JQogIG11dGF0ZV9hdCh2YXJzKC12YWx1ZSksYXMuZmFjdG9yKSAlPiUKICBkcGx5cjo6cmVuYW1lKHByZWRpY3RvciA9IHZhcklEQVEpICU+JQogIGdncGxvdCguLCBhZXModmFsdWUsIGZpbGwgPSBwcmVkaWN0b3IpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjUpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIiwgbGluZXR5cGUgPSAyKSArCiAgZ2d0aXRsZShwYXN0ZSgiUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgYWNyb3NzIHRoZSB0d28gbmV0d29ya3MiKSkgKyAKICBmYWNldF93cmFwKH5uZXR3b3JrKSArCiAgY29vcmRfZml4ZWQocmF0aW8gPSAxLzQwKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkrIAogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgOS41IEhESStST1BFIGRlY2lzaW9uIHJ1bGUKCmBgYHtyfQoKaGRpX3JvcGUgPC0gZnVuY3Rpb24obW9kZWwpewogIHJvcGUgPC0gcm9wZV9yYW5nZShtb2RlbCkKICByb3BlX21vZGVsIDwtIGVxdWl2YWxlbmNlX3Rlc3QobW9kZWwsIHJhbmdlID0gcm9wZSwgY2kgPSAwLjk1KSAKICAjcm9wZV9tb2RlbCAlPiUgbXV0YXRlKHJvaSA9IGFzLmNoYXJhY3Rlcihtb2RlbCRmaWxlKSkKICBwbG90KHJvcGVfbW9kZWwpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgICBnZ3RpdGxlKGRlcGFyc2Uoc3Vic3RpdHV0ZShtb2RlbCkpKSArIAogICAgeGxpbSgtMC4xNSwwLjE1KSArICAKICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSAKICAgICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwNzJCMiIsICIjRDU1RTAwIikpCn0KCmhkaV9yb3BlKHRvbSkgKyBoZGlfcm9wZShwYWluKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgIAoKCihoZGlfcm9wZShydHBqKSAvIGhkaV9yb3BlKGx0cGopIC8gaGRpX3JvcGUocHJlYykpICYKKGhkaV9yb3BlKHZtcGZjKSAvIGhkaV9yb3BlKG1tcGZjKSAvIGhkaV9yb3BlKGRtcGZjKSkgKyBwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcpICAKCihoZGlfcm9wZShydHBqKSB8IGhkaV9yb3BlKGx0cGopKSAvCihoZGlfcm9wZShwcmVjKSB8IGhkaV9yb3BlKHZtcGZjKSkgLwooaGRpX3JvcGUobW1wZmMpIHwgaGRpX3JvcGUoZG1wZmMpKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgIAoKCmBgYAoKIyAxMC4gQ29udHJvbCBhbmFseXNlcyB7LnRhYnNldH0KCiMjMTAuMSBUaGVvcnktb2YtTWluZCBuZXR3b3JrClVwZGF0ZSB0aGUgbW9kZWxzIGJ5IHJlbW92aW5nIHRoZSAxNiBwYXJ0aWNpcGFudHMgdGhhdCBjb21wbGV0ZWQgYSBkaWZmZXJlbnQgdmVyc2lvbiBvZiB0aGUgSURBUSAoMS0xMCkuIFdlIGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIGRvIHRoaXM6CmBgYHtyfQoKdXBkYXRlX21vZGVsIDwtIGZ1bmN0aW9uKG1vZGVsX29sZCwgcmVnaW9uKXsKICBtb2RlbF9uZXcgPC0gdXBkYXRlKG1vZGVsX29sZCwgbmV3ZGF0YSA9IERGLnJvaSAlPiUgZmlsdGVyKHJvaSA9PSByZWdpb24gJiAhc3ViICVpbiUgc3ViX2V4KSwgc2VlZCA9IDQxKQogIAogIG0xIDwtIHBvc3Rlcmlvcl9zdW1tYXJ5KG1vZGVsX29sZClbYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIikgLCAiRXN0aW1hdGUiXQogIG0yIDwtIHBvc3Rlcmlvcl9zdW1tYXJ5KG1vZGVsX25ldylbYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIikgLCAiRXN0aW1hdGUiXQogIAogIHRpYmJsZShiaWFzID0gcm91bmQoMTAwKigobTEtbTIpL20yKSwgMiksIHByZWRpY3RvciA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpKQp9CmBgYAoKQ2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIChiaWFzKSBwZXIgVG9NIHJlZ2lvbjoKYGBge3J9CnJ0cGpfYmlhcyA8LSB1cGRhdGVfbW9kZWwocnRwaiwgInJ0cGoiKQpsdHBqX2JpYXMgPC0gdXBkYXRlX21vZGVsKGx0cGosICJsdHBqIikKcHJlY19iaWFzIDwtIHVwZGF0ZV9tb2RlbChwcmVjLCAicHJlYyIpCnZtcGZjX2JpYXMgPC0gdXBkYXRlX21vZGVsKHZtcGZjLCAidm1wZmMiKQptbXBmY19iaWFzIDwtIHVwZGF0ZV9tb2RlbChtbXBmYywgIm1tcGZjIikKZG1wZmNfYmlhcyA8LSB1cGRhdGVfbW9kZWwoZG1wZmMsICJkbXBmYyIpCmBgYAoKIyMxMC4xIFBhaW4gTWF0cml4CkNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSAoYmlhcykgcGVyIFBhaW4gTWF0cml4IHJlZ2lvbjoKYGBge3J9CnJzMl9iaWFzIDwtIHVwZGF0ZV9tb2RlbChydHBqLCAicnMyIikKbHMyX2JpYXMgPC0gdXBkYXRlX21vZGVsKGx0cGosICJsczIiKQpyaW5zdWxhX2JpYXMgPC0gdXBkYXRlX21vZGVsKHByZWMsICJyaW5zdWxhIikKbGluc3VsYV9iaWFzIDwtIHVwZGF0ZV9tb2RlbCh2bXBmYywgImxpbnN1bGEiKQpybWZnX2JpYXMgPC0gdXBkYXRlX21vZGVsKG1tcGZjLCAicm1mZyIpCmxtZmdfYmlhcyA8LSB1cGRhdGVfbW9kZWwoZG1wZmMsICJsbWZnIikKYW1jY19iaWFzIDwtIHVwZGF0ZV9tb2RlbChkbXBmYywgImFtY2MiKQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=